Java垃圾回收

GC是什么?為什么要有GC?

答:GC是垃圾收集的意思,內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯(cuò)誤的內(nèi)存回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java提供的GC功能可以自動(dòng)監(jiān)測(cè)對(duì)象是否超過作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法。Java程序員不用擔(dān)心內(nèi)存管理,因?yàn)槔占鲿?huì)自動(dòng)進(jìn)行管理。要請(qǐng)求垃圾收集,可以調(diào)用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉顯示的垃圾回收調(diào)用。
垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個(gè)單獨(dú)的低優(yōu)先級(jí)的線程運(yùn)行,不可預(yù)知的情況下對(duì)內(nèi)存堆中已經(jīng)死亡的或者長(zhǎng)時(shí)間沒有使用的對(duì)象進(jìn)行清除和回收,程序員不能實(shí)時(shí)的調(diào)用垃圾回收器對(duì)某個(gè)對(duì)象或所有對(duì)象進(jìn)行垃圾回收。在Java誕生初期,垃圾回收是Java最大的亮點(diǎn)之一,因?yàn)榉?wù)器端的編程需要有效的防止內(nèi)存泄露問題,然而時(shí)過境遷,如今Java的垃圾回收機(jī)制已經(jīng)成為被詬病的東西。移動(dòng)智能終端用戶通常覺得iOS的系統(tǒng)比Android系統(tǒng)有更好的用戶體驗(yàn),其中一個(gè)深層次的原因就在于Android系統(tǒng)中垃圾回收的不可預(yù)知性。

補(bǔ)充:垃圾回收機(jī)制有很多種,包括:分代復(fù)制垃圾回收、標(biāo)記垃圾回收、增量垃圾回收等方式。標(biāo)準(zhǔn)的Java進(jìn)程既有棧又有堆。棧保存了原始型局部變量,堆保存了要?jiǎng)?chuàng)建的對(duì)象。Java平臺(tái)對(duì)堆內(nèi)存回收和再利用的基本算法被稱為標(biāo)記和清除,但是Java對(duì)其進(jìn)行了改進(jìn),采用“分代式垃圾收集”。這種方法會(huì)跟Java對(duì)象的生命周期將堆內(nèi)存劃分為不同的區(qū)域,在垃圾收集過程中,可能會(huì)將對(duì)象移動(dòng)到不同區(qū)域:

  • 伊甸園(Eden):這是對(duì)象最初誕生的區(qū)域,并且對(duì)大多數(shù)對(duì)象來說,這里是它們唯一存在過的區(qū)域。
  • 幸存者樂園(Survivor):從伊甸園幸存下來的對(duì)象會(huì)被挪到這里。
  • 終身頤養(yǎng)園(Tenured):這是足夠老的幸存對(duì)象的歸宿。年輕代收集(Minor-GC)過程是不會(huì)觸及這個(gè)地方的。當(dāng)年輕代收集不能把對(duì)象放進(jìn)終身頤養(yǎng)園時(shí),就會(huì)觸發(fā)一次完全收集(Major-GC),這里可能還會(huì)牽扯到壓縮,以便為大對(duì)象騰出足夠的空間。

一個(gè)系統(tǒng),定時(shí)任務(wù)超級(jí)多,但是每個(gè)定時(shí)任務(wù)都很短,在JVM優(yōu)化上,應(yīng)該怎么配置才能達(dá)到性能最優(yōu)

把新生代的那塊內(nèi)存設(shè)置大一點(diǎn)..
s0和s1區(qū)交換區(qū)比例

如何確定垃圾?

  • 引用計(jì)數(shù) ×
  • 從垃圾回收的根出發(fā)可見

垃圾回收根節(jié)點(diǎn)

  • 局部變量
  • 靜態(tài)變量
  • Native方法所引用的對(duì)象
  • 活動(dòng)線程,等待中的Monitor(wait,notify,synchronized)

現(xiàn)在jvm采用分代回收機(jī)制,簡(jiǎn)單來說就是分為新生代和老生代,老生代內(nèi)存空間比新生代大;大部分新對(duì)象都會(huì)優(yōu)先分配到新生代,當(dāng)新生代空間滿了會(huì)發(fā)起一次Minor GC。而新分配的大對(duì)象或者在新生代空間里存活很久的對(duì)象會(huì)被放到老生代里,老生代空間滿了會(huì)發(fā)起Major GC,但由于老生代里的對(duì)象生命周期比較長(zhǎng)加上Major GC速度比Minor GC慢很多,所以發(fā)生在老生代的Major GC相對(duì)會(huì)比Minor GC少很多。因此垃圾能不能被立即回收,要看垃圾的大小,它所處在的空間和當(dāng)前所處空間是否已滿才能基本確定。

Java分代垃圾回收算法

基礎(chǔ)假設(shè):大部分對(duì)象只存在很短的時(shí)間
將內(nèi)存分為新生代,老生代
將新生代分為Eden,Survivor1,Survivor2

新生代中 存活一定次數(shù)會(huì)被轉(zhuǎn)入老生代
Major/Full GC 會(huì)對(duì)老生代做GC
老生代GC采用Compact算法(標(biāo)記、壓縮)

參數(shù)配置:

  • -XX: NewRatio 老生代/新生代比例,默認(rèn)2
  • -XX: SurvivorRatio Eden/Survivor比例,默認(rèn)8
  • -XX: MaxTenuringThreshold 新生代轉(zhuǎn)至老生代閾值,默認(rèn)15

PermGen Space

Permanent Generation 持久代

  • 放置ClassLoader讀進(jìn)來的Class,除系統(tǒng)Class外
  • 放置String.intern后的結(jié)果
  • 易出現(xiàn)OutOfMemoryError:PermGen Space
  • 使用 -XX: MaxPermSize調(diào)整
  • Java 1.8使用Metaspace,取消持久代
  • String.intern的結(jié)果被放入堆
  • Metaspace默認(rèn)不設(shè)限制,使用系統(tǒng)內(nèi)存

垃圾回收在什么時(shí)候運(yùn)行?

內(nèi)存分配失敗時(shí)候,System.gc()

垃圾回收對(duì)什么對(duì)象進(jìn)行回收?

從垃圾回收的根節(jié)點(diǎn)出發(fā),順著引用關(guān)系的對(duì)象去找,找不到的對(duì)象進(jìn)行垃圾回收

垃圾回收算法對(duì)內(nèi)存劃分了哪些區(qū)域

新生代、老生代、持久代(MetaSpace),新生代又分為Eden,S1,S2
新生代采用了拷貝的方法,Eden+s -> s,存活時(shí)間久的話就放到老生代,
老生代采用的Compact算法,MetaSpace放一些class Object

垃圾回收的調(diào)試

獲取信息
-verbose:gc
-XX:+HeapDumpOnOutOfMemoryError
-XX:+PrintGCDetails -Xloggc:<GC-log-file-path>
Spring Actuator

查看信息
官方: visualvm,jmap
Eclipse Memory Analyzer(MAT)
在線: gceasy.io fastthread.io

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容