Java分代垃圾回收策略原理詳解
一、為什么要分代
分代的垃圾回收策略,是基于這樣一個(gè)事實(shí):不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。
在Java程序運(yùn)行的過程中,會產(chǎn)生大量的對象,其中有些對象是與業(yè)務(wù)信息相關(guān),比如Http請求中的Session對象、線程、Socket連接,這類對象跟業(yè)務(wù)直接掛鉤,因此生命周期比較長。但是還有一些對象,主要是程序運(yùn)行過程中生成的臨時(shí)變量,這些對象生命周期會比較短,比如:String對象,由于其不變類的特性,系統(tǒng)會產(chǎn)生大量的這些對象,有些對象甚至只用一次即可回收。
試想,在不進(jìn)行對象存活時(shí)間區(qū)分的情況下,每次垃圾回收都是對整個(gè)堆空間進(jìn)行回收,花費(fèi)時(shí)間相對會長,同時(shí),因?yàn)槊看位厥斩夹枰闅v所有存活對象,但實(shí)際上,對于生命周期長的對象而言,這種遍歷是沒有效果的,因?yàn)榭赡苓M(jìn)行了很多次遍歷,但是他們依舊存在。因此,分代垃圾回收采用分治的思想,進(jìn)行代的劃分,把不同生命周期的對象放在不同代上,不同代上采用最適合它的垃圾回收方式進(jìn)行回收。
二、如何分代
如圖所示:

虛擬機(jī)中的共劃分為三個(gè)代:年輕代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關(guān)系不大。年輕代和年老代的劃分是對垃圾收集影響比較大的。
年輕代:
所有新生成的對象首先都是放在年輕代的。年輕代的目標(biāo)就是盡可能快速的收集掉那些生命周期短的對象。年輕代分三個(gè)區(qū)。一個(gè)Eden區(qū),兩個(gè)Survivor區(qū)(一般而言)。大部分對象在Eden區(qū)中生成。當(dāng)Eden區(qū)滿時(shí),還存活的對象將被復(fù)制到Survivor區(qū)(兩個(gè)中的一個(gè)),當(dāng)這個(gè)Survivor區(qū)滿時(shí),此區(qū)的存活對象將被復(fù)制到另外一個(gè)Survivor區(qū),當(dāng)這個(gè)Survivor區(qū)也滿了的時(shí)候,從第一個(gè)Survivor區(qū)復(fù)制過來的并且此時(shí)還存活的對象,將被復(fù)制“年老區(qū)(Tenured)”。需要注意,Survivor的兩個(gè)區(qū)是對稱的,沒先后關(guān)系,所以同一個(gè)區(qū)中可能同時(shí)存在從Eden復(fù)制過來的對象,和從前一個(gè)Survivor復(fù)制過來的對象,而復(fù)制到年老區(qū)的只有從第一個(gè)Survivor區(qū)過來的對象。而且,Survivor區(qū)總有一個(gè)是空的。同時(shí),根據(jù)程序需要,Survivor區(qū)是可以配置為多個(gè)的(多于兩個(gè)),這樣可以增加對象在年輕代中的存在時(shí)間,減少被放到年老代的可能。
新生代有劃分為Eden、From Survivor和To Survivor三個(gè)部分,他們對應(yīng)的內(nèi)存空間的大小比例為8:1:1,也就是,為對象分配內(nèi)存的時(shí)候,首先使用Eden空間,經(jīng)過GC后,沒有被回收的會首先進(jìn)入From Survivor區(qū)域,任何時(shí)候,都會保持一個(gè)Survivorq區(qū)域(From Survivor或To Survivor)完全空閑,也就是說新生代的內(nèi)存利用率最大為90%。From Survivor和To Survivor兩個(gè)區(qū)域會根據(jù)GC的實(shí)際情況,進(jìn)行互換,將From Survivor區(qū)域中的對象全部復(fù)制到To Survivor區(qū)域中,或者反過來,將To Survivor區(qū)域中的對象全部復(fù)制到From Survivor區(qū)域中。
年老代:
在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認(rèn)為年老代中存放的都是一些生命周期較長的對象。
GC過程中,當(dāng)某些對象經(jīng)過多次GC都沒有被回收,可能會進(jìn)入到年老代。或者,當(dāng)新生代沒有足夠的空間來為對象分配內(nèi)存時(shí),可能會直接在年老代進(jìn)行分配。
持久代:
用于存放靜態(tài)文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應(yīng)用可能動態(tài)生成或者調(diào)用一些class,例如Hibernate等,在這種時(shí)候需要設(shè)置一個(gè)比較大的持久代空間來存放這些運(yùn)行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進(jìn)行設(shè)置。
永久代實(shí)際上對應(yīng)著虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的“方法區(qū)”,這里主要存放類信息、靜態(tài)變量、常量等數(shù)據(jù)。一般情況下,永久代中對應(yīng)的對象的GC效率非常低,因?yàn)檫@里的的大部分對象在運(yùn)行都不要進(jìn)行GC,它們會一直被利用,直到JVM退出。
三、什么情況下觸發(fā)垃圾回收
由于對象進(jìn)行了分代處理,因此垃圾回收區(qū)域、時(shí)間也不一樣。GC有兩種類型:Scavenge GC和Full GC。
Scavenge GC
一般情況下,當(dāng)新對象生成,并且在Eden申請空間失敗時(shí),就會觸發(fā)Scavenge GC,對Eden區(qū)域進(jìn)行GC,清除非存活對象,并且把尚且存活的對象移動到Survivor區(qū)。然后整理Survivor的兩個(gè)區(qū)。這種方式的GC是對年輕代的Eden區(qū)進(jìn)行,不會影響到年老代。因?yàn)榇蟛糠謱ο蠖际菑腅den區(qū)開始的,同時(shí)Eden區(qū)不會分配的很大,所以Eden區(qū)的GC會頻繁進(jìn)行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。
對整個(gè)堆進(jìn)行整理,包括Young、Tenured和Perm。Full GC因?yàn)樾枰獙φ麄€(gè)塊進(jìn)行回收,所以比Scavenge GC要慢,因此應(yīng)該盡可能減少Full GC的次數(shù)。在對JVM調(diào)優(yōu)的過程中,很大一部分工作就是對于FullGC的調(diào)節(jié)。有如下原因可能導(dǎo)致Full GC:
- · 年老代(Tenured)被寫滿
- · 持久代(Perm)被寫滿
- · System.gc()被顯示調(diào)用
- ·上一次GC之后Heap的各域分配策略動態(tài)變化
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
解決Aop @AfterReturning因返回類型不一致導(dǎo)致無法執(zhí)行切面代碼
這篇文章主要介紹了解決Aop @AfterReturning因返回類型不一致導(dǎo)致無法執(zhí)行切面代碼問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
Maven多個(gè)項(xiàng)目實(shí)現(xiàn)聚合過程解析
這篇文章主要介紹了Maven多個(gè)項(xiàng)目實(shí)現(xiàn)聚合過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
SpringBoot整合新版SpringSecurity完整過程
Spring Security是保障Spring應(yīng)用程序安全的強(qiáng)大框架,而新版的Spring Security引入了lambda表達(dá)式來配置,使得安全配置更加簡潔、優(yōu)雅,本文將介紹如何在Spring Boot項(xiàng)目中整合新版Spring Security,需要的朋友可以參考下2024-02-02
Java?OpenCV學(xué)習(xí)之Mat的基本操作詳解
OpenCV用來存儲圖像,很多時(shí)候都會用到這個(gè)Mat方法。數(shù)字圖像可看做一個(gè)數(shù)值矩陣,?其中的每一個(gè)元素表明一個(gè)像素點(diǎn)。Mat在?OpenCV?中表示的是?N?維稠密矩陣,與稠密矩陣相對的是稀疏矩陣。本文將重點(diǎn)介紹OpenCV中Mat的一些基本操作,需要的可以參考一下2022-03-03
Idea 解決 Could not autowire. No beans of ''xxxx'' type found
這篇文章主要介紹了Idea 解決 Could not autowire. No beans of 'xxxx' type found 的錯誤提示,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
SpringCloud Zuul過濾器實(shí)現(xiàn)登陸鑒權(quán)代碼實(shí)例
這篇文章主要介紹了SpringCloud Zuul過濾器實(shí)現(xiàn)登陸鑒權(quán)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03

