柚子快報邀請碼778899分享:JVM 垃圾回收分配及算法
柚子快報邀請碼778899分享:JVM 垃圾回收分配及算法
一、判斷對象是否可以回收
垃圾收集器在做垃圾回收的時候,首先需要判定的就是哪些內(nèi)存是需要被回收 的,哪些對象是「存活」的,是不可以被回收的;哪些對象已經(jīng)「死掉」了,需 要被回收。 一般有兩種方法來判斷:
????????引用計數(shù)器法:為每個對象創(chuàng)建一個引用計數(shù),有對象引用時計數(shù)器 +1,引用被釋放時計數(shù) -1,當計數(shù)器為 0 時就可以被回收。它有一個缺點不能解決循環(huán)引用的問題;
????????可達性分析算法:從 GC Roots 開始向下搜索,搜索所走過的路徑稱為引用鏈。 當一個對象到 GC Roots 沒有任何引用鏈相連時,則證明此對象是可以被回收的。
二、堆空間分配年輕代老年代及對應(yīng)回收算法
堆主要用于存放各種類的實例對象和數(shù)組。在java中被分為兩個區(qū)域:年輕代和老年代。?
年輕代和老年代的劃分是為了更好的內(nèi)存分派及回收。提高效率。堆是垃圾回收機制的重點區(qū)域。我們知道垃圾回收機制有三種,minor gc,major gc 和full gc。針對于堆的就是前兩種。年輕代的叫 minor gc,老年代的叫major gc。?
1. 年輕代
年輕代中存在的對象是死亡非常快的,存在朝生夕死的情況。尺寸隨堆大小的增加和減少而相應(yīng)的變化,默認值是保持為堆的1/15。所以為了提高年輕代的垃圾回收效率,又將年輕代劃分為三個區(qū)域:?Eden區(qū)、SurvivorFrom區(qū)、SurvivorTo區(qū)。
eden和survivor默認比例是8:1:1,進行垃圾回收采用的是分代復制算法(優(yōu)點是避免內(nèi)存碎片)。新創(chuàng)建的對象都會被分配到Eden區(qū)(如果該對象占用內(nèi)存非常大,則直接分配到老年代區(qū)),當Eden區(qū)內(nèi)存不夠的時候就會觸發(fā)MinorGC(Survivor滿不會引發(fā)MinorGC,而是將對象移動到老年代中),?每次新生代的使用,會是eden區(qū)和一塊survivor區(qū)。當我們進行垃圾回收的時候,清除正在使用的區(qū)域,將其中的存貨對象,放入到另一個survivor區(qū)域,并進行整理,保證空間的連續(xù)。如果對象長時間存活,則將對象移動到老年區(qū)?!癋rom”區(qū)和“To”區(qū)互換角色,原Survivor To成為下一次GC時的Survivor From區(qū), 總之,GC后,都會保證Survivor To區(qū)是空的。存活下來的對象,他的年齡會增長1。當對象的年齡一次次存活,一次次增長,到達15的時候,這些對象就會移步到老年代。在年輕代執(zhí)行g(shù)c的時候,如果老年代的連續(xù)空間小于新生代對象的總大小,就會觸發(fā)一次full gc。是為了給新生代做擔保,保證新生代的老年對象可以順利的進入到老年代的內(nèi)存區(qū)。
2. 老年代
隨著Minor GC的持續(xù)進行,老年代中對象(年齡大于15的對象)也會持續(xù)增長,導致老年代的空間也會不夠用,最終會執(zhí)行Major GC(或full gc)(MajorGC 的速度比 Minor GC 慢很多很多,據(jù)說10倍左右),full gc會包含年輕代的gc。但老年代只要執(zhí)行g(shù)c就一定是full gc。full gc使用的算法是:標記清除(回收)算法或標記壓縮算法。
標記無用對象,然后進行清除回收。 標記-清除算法(Mark-Sweep)是一種常見的基礎(chǔ)垃圾收集算法,當進行標記清除時,會停止整個程序(stop the world),它將垃圾收集分為兩個階段:
????????標記階段:從根節(jié)點開始遍歷,標記所有被引用的對象,一般在對象的header中標記為可達對象。
????????清除階段:collector對堆內(nèi)存從頭到尾進行線性遍歷,如果發(fā)現(xiàn)某個對象的header沒有標記為可達對象,則回收?。這里的回收是把對象的地址保存在空閑的地址列表中(內(nèi)存分配),下次對象需要加載時,判斷垃圾的位置空間是否夠,如果夠就存放覆蓋原有的地址。
優(yōu)點:實現(xiàn)簡單,不需要對象進行移動。
缺點:標記、清除過程效率低,產(chǎn)生大量不連續(xù)的內(nèi)存碎片,提高了垃圾回收的頻率。?
3.?永久代(元空間)
在Java8中,永久代已經(jīng)被移除,被一個稱為“元數(shù)據(jù)區(qū)”(元空間,Metaspace)的區(qū)域所取代。 值得注意的是:元空間并不在虛擬機中,而是使用本地內(nèi)存(之前,永久代是在jvm中)。這樣,解決了以前永久代的OOM問題,元數(shù)據(jù)和class對象存在永久代中,容易出現(xiàn)性能問題和內(nèi)存溢出,畢竟是和老年代共享堆空間。java8后,永久代升級為元空間獨立后,也降低了老年代GC的復雜度。
元空間也是對java虛擬機的方法區(qū)的一種實現(xiàn)。元空間與永久代最大的區(qū)別在于,元空間不在虛擬機中,使用本地內(nèi)存。通過配置如下參數(shù)可以更改元空間的大小。 ????????-XX:MetaspaceSize:初始空間的大小。達到該值就會觸發(fā)垃圾收集進行類型卸載,同時GC會對該值進行調(diào)整:如果釋放了大量的空間,就適當降低該值;如果釋放了很少的空間,那么在不超過MaxMetaspaceSize時,適當提高該值。 ????????-XX:MaxMetaspaceSize,最大空間,默認是沒有限制的。 永久代的回收會隨著full gc進行移動,消耗性能。每種類型的垃圾回收都需要特殊處理元數(shù)據(jù)。將元數(shù)據(jù)剝離出來,簡化了垃圾收集,提高了效率。
三、其他垃圾回收算法
1.?復制算法(年輕代使用)
為了解決標記-清除算法的效率不高的問題,產(chǎn)生了復制算法。它把內(nèi)存空間劃為兩個相等的區(qū)域,每次只使用其中一個區(qū)域。垃圾收集時,遍歷當前使用的區(qū)域,把存活對象復制到另外一個區(qū)域中,最后將當前使用的區(qū)域的可回收的對象進行回收。
優(yōu)點:按順序分配內(nèi)存即可,實現(xiàn)簡單、運行高效,不用考慮內(nèi)存碎片。
缺點:可用的內(nèi)存大小縮小為原來的一半,對象存活率高時會頻繁進行復制。
2. 標記-整理算法(標記壓縮算法)
在新生代中可以使用復制算法,但是在老年代就不能選擇復制算法了,因為老年代的對象存活率會較高,這樣會有較多的復制操作,導致效率變低。標記-清除算法可以應(yīng)用在老年代中,但是它效率不高,在內(nèi)存回收后容易產(chǎn)生大量內(nèi)存碎 片。因此就出現(xiàn)了一種標記-整理算法(Mark-Compact)算法,與標記-清除算法不同的是,在標記可回收的對象后將所有存活的對象壓縮到內(nèi)存的一端,使他們緊湊的排列在一起,然后對端邊界以外的內(nèi)存進行回收?;厥蘸?,已用和未用的內(nèi)存都各自一邊。
優(yōu)點:解決了標記-清理算法存在的內(nèi)存碎片問題。
缺點:仍需要進行局部對象移動,一定程度上降低了效率。
參考:
JVM年輕代,老年代,永久代詳解 - 經(jīng)典雞翅 - 博客園 (cnblogs.com)
jvm之年輕代(新生代)、老年代、永久代以及GC原理詳解_老年代空間多大-CSDN博客
柚子快報邀請碼778899分享:JVM 垃圾回收分配及算法
精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。