垃圾回收算法值漫、回收機制與總結(jié) ---JVM
一伯诬、垃圾回收算法
1.標記清除
標記--清除算法將垃圾回收分為兩個階段:標記階段和清除階段晚唇。
在標記階段首先通過根節(jié)點(GC Roots),標記所有從根節(jié)點開始的對象盗似,未被標記的對象就是未被引用的垃圾對象哩陕。然后,在清除階段赫舒,清除所有未被標記的對象悍及。如下圖
[圖片上傳失敗...(image-601690-1618061506012)]
適用場景:
- 對于存活對象較多的情況下比較高效
- 適用于年老代(即舊生代)
缺點:
- 容易產(chǎn)生內(nèi)存碎片,再來一個比較大的對象時(典型情況:該對象的大小大于空閑表中的每一塊兒大小但是小于其中兩塊兒的和)接癌,會提前觸發(fā)垃圾回收
- 掃描了整個空間兩次(第一次:標記存活對象心赶;第二次:清除沒有標記的對象)
2.復制算法
從根集合節(jié)點進行掃描,標記出所有的存活對象缺猛,并將這些存活的對象復制到一塊兒新的內(nèi)存(圖中下邊的那一塊兒內(nèi)存)上去缨叫,之后將原來的那一塊兒內(nèi)存(圖中上邊的那一塊兒內(nèi)存)全部回收掉
[圖片上傳失敗...(image-9bc14e-1618061506011)]
現(xiàn)在很多的的商業(yè)虛擬機都采用這種收集算法來回收新生代。
適用場合:
- 存活對象較少的情況下比較高效
- 掃描了整個空間一次(標記存活對象并復制移動)
- 適用于年輕代(即新生代):基本上98%的對象是"朝生夕死"的荔燎,存活下來的會很少
缺點:
- 需要一塊兒空的內(nèi)存空間
- 需要復制移動對象
3.標記整理
復制算法的高效性是建立在存活對象少耻姥、垃圾對象多的前提下的。
這種情況在新生代經(jīng)常發(fā)生有咨,但是在老年代更常見的情況是大部分對象都是存活對象琐簇。如果依然使用復制算法,由于存活的對象較多摔吏,復制的成本也將很高鸽嫂。
[圖片上傳失敗...(image-ee4c8c-1618061506011)]
標記-壓縮算法是一種老年代的回收算法纵装,它在標記-清除算法的基礎上做了一些優(yōu)化。
首先也需要從根節(jié)點開始對所有可達對象做一次標記据某,但之后橡娄,它并不簡單地清理未標記的對象,而是將所有的存活對象壓縮到內(nèi)存的一端癣籽。之后挽唉,清理邊界外所有的空間。這種方法既避免了碎片的產(chǎn)生筷狼,又不需要兩塊相同的內(nèi)存空間瓶籽,因此,其性價比比較高埂材。
4.分代收集算法
分代收集算法就是目前虛擬機使用的回收算法塑顺,它解決了標記整理不適用于老年代的問題,將內(nèi)存分為各個年代俏险。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation)严拒,在堆區(qū)之外還有一個代就是永久代(Permanet Generation)。
在不同年代使用不同的算法竖独,從而使用最合適的算法裤唠,新生代存活率低,可以使用復制算法莹痢。而老年代對象存活率搞种蘸,沒有額外空間對它進行分配擔保,所以只能使用標記清除或者標記整理算法竞膳。
二航瞭、垃圾回收機制
jvm內(nèi)存結(jié)構(gòu)
1)新產(chǎn)生的對象優(yōu)先分配在Eden區(qū)(除非配置了-XX:PretenureSizeThreshold,大于該值的對象會直接進入年老代)顶猜;
2)當Eden區(qū)滿了或放不下了沧奴,這時候其中存活的對象會復制到from區(qū)。
這里长窄,需要注意的是滔吠,如果存活下來的對象from區(qū)都放不下,則這些存活下來的對象全部進入年老代挠日。之后Eden區(qū)的內(nèi)存全部回收掉疮绷。
3)之后產(chǎn)生的對象繼續(xù)分配在Eden區(qū),當Eden區(qū)又滿了或放不下了嚣潜,這時候?qū)袳den區(qū)和from區(qū)存活下來的對象復制到to區(qū)(同理冬骚,如果存活下來的對象to區(qū)都放不下,則這些存活下來的對象全部進入年老代),之后回收掉Eden區(qū)和from區(qū)的所有內(nèi)存只冻。
4)如上這樣庇麦,會有很多對象會被復制很多次(每復制一次,對象的年齡就+1)喜德,默認情況下山橄,當對象被復制了15次(這個次數(shù)可以通過:-XX:MaxTenuringThreshold來配置),就會進入年老代了舍悯。
5)當年老代滿了或者存放不下將要進入年老代的存活對象的時候航棱,就會發(fā)生一次Full GC(這個是我們最需要減少的,因為耗時很嚴重)萌衬。
垃圾回收有兩種類型:Minor GC 和 Full GC饮醇。
1.Minor GC
對新生代進行回收,不會影響到年老代秕豫。因為新生代的 Java 對象大多死亡頻繁朴艰,所以 Minor GC 非常頻繁,一般在這里使用速度快馁蒂、效率高的算法呵晚,使垃圾回收能盡快完成。
2.Full GC
也叫 Major GC沫屡,對整個堆進行回收,包括新生代和老年代撮珠。由于Full GC需要對整個堆進行回收沮脖,所以比Minor GC要慢,因此應該盡可能減少Full GC的次數(shù)芯急,導致Full GC的原因包括:老年代被寫滿勺届、永久代(Perm)被寫滿和System.gc()被顯式調(diào)用等。
二娶耍、垃圾回收算法總結(jié)
1.年輕代:復制算法
所有新生成的對象首先都是放在年輕代的免姿。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。
新生代內(nèi)存按照8:1:1的比例分為一個eden區(qū)和兩個survivor(survivor0,survivor1)區(qū)榕酒。一個Eden區(qū)胚膊,兩個 Survivor區(qū)(一般而言)。大部分對象在Eden區(qū)中生成想鹰∥赏瘢回收時先將eden區(qū)存活對象復制到一個survivor0區(qū),然后清空eden區(qū)辑舷,當這個survivor0區(qū)也存放滿了時喻犁,則將eden區(qū)和survivor0區(qū)存活對象復制到另一個survivor1區(qū),然后清空eden和這個survivor0區(qū),此時survivor0區(qū)是空的肢础,然后將survivor0區(qū)和survivor1區(qū)交換还栓,即保持survivor1區(qū)為空, 如此往復传轰。
當survivor1區(qū)不足以存放 eden和survivor0的存活對象時剩盒,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發(fā)一次Full GC(Major GC)路召,也就是新生代勃刨、老年代都進行回收。
新生代發(fā)生的GC也叫做Minor GC股淡,MinorGC發(fā)生頻率比較高(不一定等Eden區(qū)滿了才觸發(fā))身隐。
2.年老代:標記-清除或標記-整理
在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中唯灵。因此贾铝,可以認為年老代中存放的都是一些生命周期較長的對象。
內(nèi)存比新生代也大很多(大概比例是1:2)埠帕,當老年代內(nèi)存滿時觸發(fā)Major GC即Full GC垢揩,F(xiàn)ull GC發(fā)生頻率比較低,老年代對象存活時間比較長敛瓷,存活率標記高叁巨。
以上這種年輕代與年老代分別采用不同回收算法的方式稱為"分代收集算法",這也是當下企業(yè)使用的一種方式
3)每一種算法都會有很多不同的垃圾回收器去實現(xiàn)呐籽,在實際使用中锋勺,根據(jù)自己的業(yè)務特點做出選擇就好。