JVM學習筆記——垃圾回收篇( 七 )


文章插圖
我們做簡單介紹:

  • 黑色是已經標記結束的內存
  • 灰色是正在標記的內存
  • 白色是未標記的內存
我們針對上述進行分析:
  • 最左側是根,黑色,已經被標記
  • 上方為根的直接/間接引用對象 , 黑色,已經被標記
  • 下方為根的直接/間接引用對象,灰色,正在標記 , 白色,還未被標記當后面會被標記
  • 最右側孤零零的白色方塊,沒有被引用,不會被標記,最后會被當作垃圾回收對象處理掉
這時我們就會發現一個問題:
  • 如果最右側的方塊在針對自身的CPU的并發標記結束后 , 又被其他進程所調用了(并發標記其他CPU正常運行)
  • 但是此時它是白色的,最終會被這次的垃圾回收操作清除掉,就會導致影響其他進程操作
所以我們設計了Remark重新標記操作:
  • 如果在該方塊針對自身的并發標記結束后又被其他進程調用,這時將他拖入一個隊列中,并將其變為灰色
  • 在并發標記結束后進入重新標記階段,就會檢查該隊列 , 若發現灰色對象,在隊列中將它變為黑色對象并排出隊列
G1垃圾回收器重要更新下面我們將會針對G1垃圾回收器在各個版本的重要更新做個介紹
JDK 8u20 字符串去重我們首先要明白字符串在底層是采用char數組形成的:
String s1 = new String("hello"); // char[]{'h','e','l','l','o'}String s2 = new String("hello"); // char[]{'h','e','l','l','o'}如果重復的字符串都存放在內存中肯定會導致內存多余占用,所以提供了解決方案:
  • 將所有新分配的字符串放入一個隊列
  • 當新生代回收時,G1并發檢查是否有字符串重復
  • 如果它們值一樣,讓它們引用同一個 char[]
  • 注意與 String.intern() 不一樣:一個底層針對String類型 , 一個底層針對char[]類型
其優缺點:
  • 優點:節省大量內存
  • 缺點:略微增多了CPU時間 , 新生代回收時間略微增多
JDK 8u40 并發標記類卸載當所有的類都經過并發標記后,就會直到哪些類不再被使用
這時如果一個類加載器的所有類都不再使用時,我們就可以卸載它所加載的所有類
JDK 8u60 回收巨型對象首先我們介紹一下巨型對象的定義:
  • 一個對象大于 region 的一半時,稱之為巨型對象
    然后我們再來介紹G1對巨型對象的處理方法:
  • 回收時被優先考慮
  • G1 不會對巨型對象進行拷貝
  • G1 會跟蹤老年代所有 incoming 引用,這樣老年代 incoming 引用為0 的巨型對象就可以在新生代垃圾回收時處理掉
垃圾回收調優本小節將會介紹垃圾回收的調優機制
基本調優概念我們進行調優需要掌握的基本知識:
  • 掌握相關工具使用
  • 掌握基本的空間調整
  • 掌握GC相關的VM參數
  • 明白調優并非固定公式 , 而是需要結合應用,環境
我們調優的領域并非只有垃圾回收,但是這個部分的調優確實會給項目帶來很大的速率優化 , 此外還有其他方法的調優:
  • IO調優
  • 鎖競爭調優
  • CPU占用調優
此外我們需要確定調優的目標:
  • 是為了保證低延遲還是為了保證高吞吐量
最快的GC是不發生GC首先我們需要明白GC是花費時間的,如果我們能夠控制好內存保證不發生GC,那么才是最快的
如果我們頻繁發生GC操作 , 那么我們就需要先進行自我反思:
  1. 存放的數據是否過多?
/*例如我們是否設置了相同元素篩???错误账簼a夠捍媯?*/
  1. 數據表示是否臃腫?
/*例如我們調取數據時是否只調取了我們所需數據還是全盤托出?例如我們選擇數據類型時是否是以最低標準為要求,數據庫能采用tiny不要使用int*/
  1. 是否存在內存泄露?
/*例如我們是否設置緩存數據時采用了Static形式的Map并不斷存儲數據?*/新生代調優首先我們先來回顧一下新生代的優點: