JAVA虛擬機--垃圾回收算法

三個問題
1.哪些內存需要回收
2.什麼時候回收
3.如何回收


1.主要的回收對象是JAVA堆裏面的對象,這裏的空間佔了大多數空間。
這裏面哪些對象要回收呢?主要是一些死掉的對象,也就是沒有被引用的對象。
判斷這些對象有兩種算法:
①引用計數算法:每個對象加一個引用計數器,每次引用一次對象,計數器加一;引用失效,計數器減一。
   缺點:無法解決循環引用的問題。
②可達性算法分析:通過一系列的GC ROOTS對象最爲起始點,往下找對象,如果一個對象的引用鏈沒有ROOTS對象,說明這個對象以失效
GC ROOTS對象可以是:虛擬機棧引用的對象、方法區中類靜態屬性引用的對象,方法區中常量引用的對象,本地方法棧中的JNI

2.什麼時候回收?
首先要說說目前大多數商用的虛擬機都採用分代垃圾收集。
也就是把內存分爲兩代,新生代和老年代。
新生代內存又分爲兩種類型Edem區和Survivor區。Survicor區又分爲Survivor From區 和Survivor To區。
其中Edem區佔新生代80%的空間,兩個Survivor區各佔10%的空間(空間分配的原因下面會說)

上面是科普,那麼什麼時候開始回收內存呢?
①JAVA虛擬機分配新的對象一般分配到新生代的Edem區和Survivor From區,
當這兩個區的內存放不下的時候,這時系統開始GC(垃圾回收),並且把GC後存活下來的對象轉移到Survivor區
②循環往復1的過程之後,直到Survivor To區放不下第一步GC存活的對象,這些對象就會都移到老年代

3.如何回收?
根據上面可以知道有兩步需要回收內存。
1.新生代Edem+Survivor區-->Survivor To區:這裏常用到的是①複製算法
2新生代Survivor To 區-->老生代區 這裏常用的是③標記-整理算法

接下來具體講一下上述算法
首先講一下最基礎的算法
①標記-清除算法:就像名字一樣,分爲兩步,標記和清除。標記就是用1裏的那兩種算法①引用計數算法②可達性算法分析
對無效的對象進行標記,清除就直接回收內存,不做其他處理。
缺點:很明顯,首先效率不高,兩步的效率都並不高,其次空間問題,清除之後會產生大量不連續的空間

爲了解決上述的問題,下面的複製算法就出來了
②複製算法:複製算法的原始是這樣的,將內存分爲兩大塊,當其中一塊內存裝滿之後,進行一次GC,
將還存活的對象轉移到另一塊內存中,但是這樣相當於每次只用一半的內存,損耗就比較大。於是在實際運用中,
也就是新生代的回收,是將其中一塊分配90%的空間(Edem+Survivor區 ),另一塊分配10%的空間(Survivor To 區 ),
這樣相當於,利用了90%的空間,大大節約了空間。
缺點:還是不能完整利用所有空間,而且對存活率比較高時要進行很多次操作,而且效率會很低。
但是就新生代這種存活率很低的情況下還是很合適的,而且使用這種算法的前提條件是還有塊額外的空間提供擔保,對於新生代來說就是老年代擔保。

③標記-整理算法
這個算法就是在①的基礎上,在清除之後,對內存進行整理,讓存活的對象向一端移動。
老年代沒有擔保的空間,所有而且老年代對象存活率較高,適合這種算法進行內存回收。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章