Java JVM:垃圾回收(GC 在什麼時候,對什麼東西,做了什麼事情)
在什麼時候:
首先需要知道,GC又分為minor GC 和 Full GC(major GC)。Java堆記憶體分為新生代和老年代,新生代
中又分為1個eden區和兩個Survior區域。
一般情況下,新建立的物件都會被分配到eden區,這些物件經過一個minor gc後仍然存活將會被移動到
Survior區域中,物件在Survior中沒熬過一個Minor GC,年齡就會增加一歲,當他的年齡到達一定程度時,
就會被移動到老年代中。
當eden區滿時,還存活的物件將被複制到survior區,當一個survior區滿時,此區域的存活物件將被複制到另外一個
survior區,當另外一個也滿了的時候,從前一個Survior區複製過來的並且此時還存活的物件,將可能被複制到老年代
因為年輕代中的物件基本都是朝生夕死(80%以上),所以年輕代的垃圾回收演算法使用的是複製演算法,
複製演算法的基本思想是將記憶體分為兩塊,每次只有其中一塊,當這一塊記憶體使用完,就將還活著的物件複製到
另一塊上面。複製演算法不會產生記憶體碎片。
在GC開始的時候,物件只會存在於eden區,和名為“From”的Survior區,Survior區“to”是空的。緊接著GC
eden區中所有存活的物件都會被複制到“To”,而在from區中,仍存活的物件會根據他們的年齡值來決定去向,
年齡到達一定只的物件會被複制到老年代,沒有到達的物件會被複制到to survior中,經過這次gc後,eden區和from
survior區已經被清空。這個時候,from和to會交換他們的角色,也就是新的to就是上次GC前的from
Minor GC:從年輕代回收記憶體
當jvm無法為一個新的物件分配空間時會觸發Minor GC,比如當Eden區滿了。
當記憶體池被填滿的時候,其中的內容全部會被複制,指標會從0開始跟蹤空閒記憶體。Eden和Survior區不存在記憶體碎片
寫指標總是停留在所使用記憶體池的頂部。執行minor操作時不會影響到永久代,從永久帶到年輕代的引用被當成
GC roots,從年輕代到永久代的引用在標記階段被直接忽略掉(永久代用來存放java的類資訊)。如果eden區域中大部分
物件被認為是垃圾,永遠也不會複製到Survior區域或者老年代空間。如果正好相反,eden區域大部分新生物件不符合GC
條件,Minor GC執行時暫停的執行緒時間將會長很多。Minor may call "stop the world";
Full GC:是清理整個堆空間包括年輕代和老年代。
那麼對於Minor GC的觸發條件:大多數情況下,直接在eden區中進行分配。如果eden區域沒有足夠的空間,
那麼就會發起一次Minor GC;對於FullGC的觸發條件:如果老年代沒有足夠的空間,那麼就會進行一次FullGC
在發生MinorGC之前,虛擬機器會先檢查老年代最大可利用的連續空間是否大於新生代所有物件的總空間。
如果大於則進行Minor GC,如果小於則看HandlePromotionFailure設定是否是允許擔保失敗(不允許則直接FullGC)
如果允許,那麼會繼續檢查老年代最大可利用的連續空間是否大於歷次晉升到老年代物件的平均大小,如果大於
則嘗試minor gc (如果嘗試失敗也會觸發Full GC),如果小於則進行Full GC。
但是,具體什麼時候執行,這個是由系統來進行決定的,是無法預測的。
對什麼東西:
主要根據可達性分析演算法,如果一個物件不可達,那麼就是可以回收的,如果一個物件可達,那麼這個物件就不可以回收,
對於可達性分析演算法,它是通過一系列稱為“GC Roots”的物件最為起始點,當一個物件GC Roots沒有任何引用鏈相接的時候,
那麼這個物件就是不可達,就可以被回收。
做了什麼事情:
主要做了清理物件,整理記憶體的工作。Java堆分為新生代和老年代,採用了不同的回收方式。
例如新生代採用了複製演算法,老年代採用了標記整理法。在新生代中,分為一個ede區域和兩個Survior
區域,真正使用的是一個eden區域,和一個Survior區域,GC的時候,會把存活的物件放入到另一個Survior區域中,
然後再把這個eden區域和Survior區域清除。那麼對於老年代,採用的是標記整理髮,首先標記出存活物件,
然後在移動到一段。這樣有利於減少記憶體碎片。
標記:標記的過程其實就是,遍歷所有gc root 然後將所有gc root 可達的物件標記為存活物件
清除:清除的過程中將遍歷堆中所有的物件,將沒有標記的物件全部清除掉
主要缺點:標記和清除過程效率不高,標記清除之後會產生大量不連續的記憶體碎片
但是,老年代中因為物件存活率高,沒有額外空間對他進行分配擔保,就必須使用標記整理演算法
標記整理演算法 標記操作和“標記-清除”演算法一致,後續操作不只是直接清理物件,而是在清理
無用物件完成後讓所有存活的物件都向一段移動,並更新其引用物件的指標
主要缺點:在標記清除的基礎上還需要進行物件的移動,成本相對比較高,成本相對較高,好處是不會產生記憶體碎片。
相關文章
- 什麼是垃圾蒐集(GC)?為什麼要有GC呢?GC
- ftp是什麼,ftp是什麼東西?FTP
- PHP中什麼是垃圾回收?對效能有什麼影響PHP
- 為什麼GC(垃圾回收)必須stop-the-world?GC
- 為什麼 JVM 需要 GCJVMGC
- 漫話:給女朋友解釋GC如何判斷什麼東西可以回收?GC
- 框架是個什麼東西?框架
- 這是什麼東西呢?
- GC是什麼?為什麼要有GC?GC
- 為什麼說區塊鏈也不是什麼好東西?區塊鏈
- C++中什麼時候用move,什麼時候用forward?C++Forward
- 什麼是介面?為什麼使用介面? 什麼時候使用介面?(轉)
- VR對老牌遊戲廠商做了什麼 他們到底在恐慌什麼VR遊戲
- 什麼時候釋出
- 什麼時候呼叫layoutSubviewsView
- javascript的垃圾回收機制指的是什麼?JavaScript
- javascript的垃圾回收機制指的是什麼JavaScript
- 來聊聊,這個Java到底是什麼東西?Java
- 什麼時候採用socket通訊,什麼時候採用http通訊HTTP
- SoftReference 到底在什麼時候被回收 ? 如何量化記憶體不足 ?記憶體
- 新版什麼時候釋出?
- 什麼時候該用vuex?Vue
- 到底什麼時候使用mqMQ
- 什麼時候該用MongoDB?MongoDB
- commit做了什麼?MIT
- EJB2.0中什麼時候用local interface,什麼時候用remote interface (轉)REM
- 安裝crs的時候sh root.sh 做了些什麼 ?
- Haskell程式設計精華:什麼時候該註釋,什麼時候不該註釋Haskell程式設計
- jquery裡面的$(this)和this都什麼時候用,有什麼區別jQuery
- 4 張動圖解釋為什麼(什麼時候)使用 Redux圖解Redux
- 開發者工具又加了什麼好東西?(Chrome 68)Chrome
- [翻譯]JDK8有什麼新東西?JDK
- GC是什麼?為什麼我們要去使用它GC
- oracle 什麼時候才回收v$session 中status='KILLED'的程式OracleSession
- C++ 為什麼不加入垃圾回收機制C++
- beego 什麼時候支援grpcGoRPC
- python什麼時候縮排Python
- session是什麼時候建立的Session