JVM的內存回收及常見算法小結
什麼樣的對象應該被回收?
某個對象不再被棧直接或間接地引用,此時就應該被回收瞭。
o被指向null的時候,new Object()創建的對象就不在被棧引用瞭,可以被回收。
p1和personList均不再指向第一個Person對象的時候,第一個Person對象、list對象可以被回收。
經歷前面的幾個階段,內存引用是這樣的情況。
p1 = null後,p1曾經指向的對象雖然不再被棧直接引用,但是仍然間接通過persons引用。
此時p1指向的對象和list指向的對象都可以被回收瞭。
怎麼樣確定哪些需要回收?
對我們仍然需要使用的對象進行標記,回收沒有標記的對象。
以此為例,如何進行標記的呢?
垃圾回收進行之前,所有對象的標記位是0
如果僅僅標記棧直接引用的對象,p1就會被回收,但是p1間接被list引用,因此也被標記為1
標記算法
-Stop the World(GC Root可達性算法)
在進行上面的標記過程的時候,如果有新的對象被創建,而剛好被標記過程錯過的時候,就可能錯誤地把有用的對象給回收掉,因為標記位是0.因此,Stop the World正如其名,將應用的核心線程停掉,開始專心標記。
-引用計數法
對對象進行引用數量的標記,沒有引用的對象標記是0,有引用的對象標記是引用數量。清除標記為0的對象即可。但是引用計數法有個問題,無法解決循環引用的問題,導致內存泄露。
這裡聲明一個對象,內部包含一個跟自己一個類型的成員變量。
在執行第五行之前,兩個對象的引用計數均為2,各自引用,加上n1和n2.
執行完第五六行以後,按道理,棧上已經不在引用這兩個對象,可以被回收瞭,但是因為n1和n2相互引用,導致引用計數為1,無法正常回收。
清除算法
一般清除算法:直接將未標記的對象清理掉
經過清理,未標記的對象被回收。
但是存在內存碎片化的問題,隻能從間隙處繼續分配內存,
存在內存不連續的問題,內存空間浪費嚴重,容易oom
清除-整理算法:先清除沒有標記的對象,然後將剩餘的存活對象進行整理,讓內存空間更加連續。
就是代價比較高,幾乎需要移動所有的對象。
復制-清除算法:將活躍的對象復制到另一個內存區域,然後清除當前區域的所有對象!
完成復制後,清除原有的區域
這種算法的弊端就是需要更多的內存空間。
常見的GC類型
GC類別 | 新生代垃圾回收 | 老年代垃圾回收 | 特點 |
Serial GC | 標記-復制&清除 |
標記-清除&整理 |
Stop the World
使用單個線程處理 適合小應用 |
Parallel GC | Java 8默認垃圾回收器
Stop the World 使用多個線程處理 |
||
CMS GC | 標記-復制&清除
(Stop the World) |
接近並行的標記-清除
初始標記->並發標記 -> 並發預清理->可中斷預清理->重新標記->並發清除->並發重置 |
|
G1 GC |
更細粒度的邏輯分區,更小的停頓時間 采用復制&整理-清理的方式,優先回收垃圾最多的區域 對字符串的合並整理,多個相同的字符串合並到一起,移除冗餘字符串對象 |
-XX:UseStringDeduplication | |
Z GC |
不在維護映射,而是對象上保持一個標記來表示活躍對象 僅支持64位系統 采用重定位解決內存碎片化問題 |
Java 15 |
到此這篇關於JVM的內存回收及常見算法的文章就介紹到這瞭,更多相關JVM的內存回收內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!