国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Java垃圾回收

2019-11-17 03:26:25
字體:
供稿:網(wǎng)友

垃圾收集算法

引用計數(shù)

堆中的每個對象都有一個引用計數(shù),當(dāng)對象被引用時引用計數(shù)加1,當(dāng)對象的引用被重新賦值或超出有效區(qū)域時引用計數(shù)減1,當(dāng)一個對象被回收后,它所引用的對象的引用計算減1。當(dāng)一個對象的引用計數(shù)變?yōu)?時就被回收。

引用計數(shù)的優(yōu)點(diǎn):

垃圾收集器可以很快地執(zhí)行,當(dāng)一個對象的引用數(shù)為0時就可以回收這個對象,垃圾收集交織在程序的正常執(zhí)行過程中,不用長時間中斷程序的正常執(zhí)行。

引用計數(shù)的缺點(diǎn):

  1. 每次引用計數(shù)的增加和減少會帶來額外的開銷
  2. 無法檢測出循環(huán)引用

根搜索算法

垃圾檢測通過建立一個根對象的集合(局部變量、棧楨中的操作數(shù),在本地方法中引用的對象,常量池等)并檢查從這些根對象開始的可觸及性來實現(xiàn)。根對象總是可訪問的,如果存在根對象到一個對象的引用路徑,那么稱這個對象是可觸及的或活動對象,否則是不可觸及的,不可觸及的對象就是垃圾對象。

標(biāo)記清除

分為標(biāo)記和清除兩個階段,在標(biāo)記階段,垃圾收集器跟蹤從根對象的引用,在追蹤的過程中對遇到的對象打一個標(biāo)記,最終未被標(biāo)記的對象就是垃圾對象,在清除階段,回收垃圾對象占用的內(nèi)存。可以在對象本身添加跟蹤標(biāo)記,也可以用一個獨(dú)立的位圖來設(shè)置標(biāo)記。

標(biāo)記清除法是基礎(chǔ)的收集算法,其他算法大多時針對這個算法缺點(diǎn)的改進(jìn)。

有兩個缺點(diǎn):

  1. 效率
  2. 存在內(nèi)存碎片

復(fù)制算法

將內(nèi)存劃分為大小相等的兩個區(qū)域,每次只使用其中的一個區(qū)域,當(dāng)這個區(qū)域的內(nèi)存用完了,就將可觸及的對象直接復(fù)制到新的區(qū)域并連續(xù)存放以消除內(nèi)存碎片,當(dāng)可觸及對象復(fù)制完后,清除舊內(nèi)存區(qū)域,修改引用的值。

這種算法的缺點(diǎn)很明顯,可使用內(nèi)存變?yōu)榱嗽瓉淼囊话耄^浪費(fèi)。

一般情況下,新生代中的對象大多生命周期很短,也就是說當(dāng)進(jìn)行垃圾收集時,大部分對象都是垃圾,只有一小部分對象會存活下來,所以只要保留一小部分內(nèi)存保存存活下來的對象就行了,用不著使用一半的內(nèi)存。在新生代中一般將內(nèi)存劃分為三個部分:一個較大的Eden空間和兩個較小的Survior空間(一樣大小),每次使用Eden和一個Survior的內(nèi)存,進(jìn)行垃圾收集時將Eden和使用的Survior中的存活的對象復(fù)制到另一個Survior空間中,然后清除這兩個空間的內(nèi)存,下次使用Eden和另一個Survior,HotSpot中默認(rèn)將這三個空間的比例劃分為8:1:1,這樣被浪費(fèi)掉的空間就只有總內(nèi)存的1/10了。

這樣的內(nèi)存空間劃分是基于這樣一種假設(shè),即每次垃圾收集時大部分對象都是垃圾,只有少部分對象存活。如果遇到例外的情況怎么辦,在某次垃圾收集時存活下來的對象超過了預(yù)留的那個Survior空間的總大小,這就需要依賴其他的內(nèi)存進(jìn)行分配擔(dān)保了(參考分代收集,前面的描述中也說了這是新生代中的方法)

標(biāo)記整理

普通的標(biāo)記清除會在內(nèi)存中留下內(nèi)存碎片,復(fù)制算法如果不想浪費(fèi)掉50%內(nèi)存就需要有內(nèi)存分配擔(dān)保,一般是內(nèi)存分代,但總有一代是沒有其他代為它擔(dān)保的。標(biāo)記整理算法中標(biāo)記的過程同標(biāo)記清理一樣,但整理部分不是直接清除掉垃圾對象,而是將活動對象統(tǒng)一移動一內(nèi)存的一端,然后清除邊界外的內(nèi)存區(qū)域,這樣就避免了內(nèi)存碎片。也不會浪費(fèi)內(nèi)存,不需要其他內(nèi)存進(jìn)行擔(dān)保

分代收集

大多數(shù)程序中創(chuàng)建的大部分對象生命周期都很短,而且會有一小部分生命周期長的對象,為了克服復(fù)制收集器中每次垃圾收集都要拷貝所有的活動對象的缺點(diǎn),將內(nèi)存劃分為不同的區(qū)域,更多地收集短生命周期所在的內(nèi)存區(qū)域,當(dāng)對象經(jīng)歷一定次數(shù)的垃圾收集存活時,提升它的存在的區(qū)域。一般是劃分為新生代和老年代。新生代又劃分為Eden區(qū),F(xiàn)rom Survior區(qū)和To Survior區(qū)。

自適應(yīng)收集器

監(jiān)聽堆中的情形,并且對應(yīng)地調(diào)用合適的垃圾收集技術(shù)。

垃圾收集器

Serial

一個單線程的收集器,在進(jìn)行垃圾收集時會暫停其他線程的工作,不適合用到Server端的虛擬機(jī),但Client模式的模擬機(jī)還是可以用的,因為Client模式下的應(yīng)用分配到的系統(tǒng)內(nèi)存一般不大,垃圾收集可以很快完成。優(yōu)點(diǎn)就是簡單高效,沒有線程交互開銷,可以獲得最高的單線程收集效率。

ParNew

Seria的多線程版本,可以多個線程收集垃圾,但如果CPU只有一核且沒有超線程,效果就不一定比Serial好了,如果是多核或有超線程,可以保證效果好于Serial,除Seria之外,這是唯一能與CMS收集器配合的垃圾收集器

Parallel Scavenge

使用復(fù)制算法的新生代多線程垃圾收集器,Parallel Scavenge收集器的關(guān)注點(diǎn)和其他收集器不同,其他收集器的關(guān)注點(diǎn)是盡可能縮短垃圾收集時用戶線程等待的時間,而Parallel Scavenge收集器的目標(biāo)是達(dá)到一個可控制的吞吐量(Throughput),即CPU用于運(yùn)行用戶代碼的時間與CPU總消耗時間的比值。以縮短用戶線程等待時間的收集器適合用于需要與用戶交互的程序,而以吞吐量為目標(biāo)的收集器適合用于不需要和用戶太多的交互,以后臺運(yùn)算為目標(biāo)的任務(wù)。

Parallel Scavenge可以通過參數(shù)設(shè)置每次垃圾收集需要停頓的時間和吞吐量目標(biāo),但停頓時間并不是越小越好,這是以犧牲吞吐量和新生代空間為代價的,因為要使垃圾收集停頓時間縮小,只能進(jìn)行少量多次收集,或減小需要收集的空間大小。

還有一個-XX:UseAdaptiveSizePolicy參數(shù),指定這個參數(shù)后,就不需要手工指定新生代的大小、Eden區(qū)和Survior區(qū)的比例大小和晉升老年代對象年齡等細(xì)節(jié)參數(shù)了,虛擬機(jī)會根據(jù)收集到的信息動態(tài)調(diào)整這些參數(shù),這稱為自適應(yīng)策略。

Serial Old

Serial的老年代版本,單線程收集器,使用"標(biāo)記-整理"算法,主要被Client模式下的虛擬機(jī)使用,當(dāng)被使用在Server模式時主要有兩個用途:

  1. 與Parallel Scavenge配合使用
  2. 作為CMS收集失敗時的備選方案。

Parallel Old

Parallel Scavenge的老年代版本,使用"標(biāo)記-整理"算法,JDK1.6后提供的,在此之前,如果新生代選擇了Parallel Scavenge,老年代只能選擇Serial Old,由于Serial Old是單線程的垃圾收集器,可能會影響收集性能。Parallel Old出現(xiàn)后,就可以分別在新生代和老年代選擇Parallel Scavenge和Parallel Old組合了。

CMS(Concurrent Mark Sweep)

以獲取最短回收停頓時間為目標(biāo)的收集器,使用“標(biāo)記-清除”算法,整個回收過程分為以下4步:

  • 初始標(biāo)記(CMS Initial Mark)
  • 并發(fā)標(biāo)記(CMS Current Mark)
  • 重新標(biāo)記(CMS Remark)
  • 并發(fā)清楚(CMS Concurrent Sweep)

初始標(biāo)記與重新標(biāo)記階段仍會暫停用戶線程的運(yùn)行。

初始標(biāo)記只是記錄下GC Root能直接關(guān)聯(lián)到的對象,速度很快。

并發(fā)標(biāo)記就是GC Roots Tracing了,速度較慢,但可以和用戶線程同時運(yùn)行。

重新標(biāo)記是修正并發(fā)標(biāo)記時由于用戶線程運(yùn)行導(dǎo)致的標(biāo)記記錄變動,這個階段會使用戶線程停頓,停頓時間比初始標(biāo)記略長,但仍小于重新標(biāo)記。

并發(fā)清除就是清除垃圾對象了,耗時較長,但可與用戶線程同時工作。

CMS的缺點(diǎn)

  1. 對CPU資源敏感,并發(fā)階段和用戶線程同時運(yùn)行,影響服務(wù)器的響應(yīng)速度,尤其是CPU核心數(shù)少時
  2. 無法處理浮動垃圾,由于并發(fā)階段用戶線程同時在運(yùn)行,可能會在垃圾收集過程中產(chǎn)生新的垃圾,CMS無法處理這部分浮動垃圾,由于在進(jìn)行垃圾收集時用戶線程同時在運(yùn)行,需要額外的內(nèi)存空間,所以不能等到內(nèi)存滿時再進(jìn)行GC,需要預(yù)留一部分空間,如果預(yù)留的這部分空間不夠GC時用戶線程創(chuàng)建新對象使用,就會使用預(yù)備方法,使用Serial Old進(jìn)行一次Full GC。
  3. CMS基于“標(biāo)記-清除”算法,進(jìn)行垃圾回收后會存在內(nèi)存碎片,當(dāng)申請大的連續(xù)內(nèi)存時可能內(nèi)存不足,此時需要進(jìn)行一次Full GC,可以通過參數(shù)指定進(jìn)行Full GC后或進(jìn)行多少次Full GC后進(jìn)行一次內(nèi)存壓縮來整理內(nèi)存碎片。

G1(Garbage First)

基于"標(biāo)記-整理"算法,避免了內(nèi)存碎片的問題,并可精確地控制垃圾回收時的停頓。

G1收集器可以實現(xiàn)基本不犧牲吞吐量的前提下完成低停頓的內(nèi)存回收,不同于之前的垃圾回收器,G1收集器的回收區(qū)域不是整個新生代或老年代,而是將整個java堆劃分為多個固定大小的區(qū)域,并跟蹤這些區(qū)域里的垃圾堆積程度,在后臺維護(hù)一個優(yōu)先列表,優(yōu)先回收垃圾最多的區(qū)域。區(qū)域的劃分使每次回收時間變短,而優(yōu)先級的劃分使得每次回收的區(qū)域可以回收最多的垃圾,這就使用G1收集器可以在有限的時間內(nèi)獲取最高的收集效率。

內(nèi)存分配與回收策略

對像優(yōu)先在新生代Eden區(qū)分配,當(dāng)Eden區(qū)沒有足夠的內(nèi)存時會發(fā)生一次Minor GC(新生代GC,Major GC或Full GC是老年代GC)

大對象可以直接在老年代分配內(nèi)存,可以通過參數(shù)指定一個大小,大于這個大小的對象直接在老年代中分配內(nèi)存。

進(jìn)行Minor GC時,Eden區(qū)和一個Survior區(qū)中存活的對象會被復(fù)制到另一個Survior區(qū),一個對象每在一次Minor GC中存活下來一次后這個對象的年齡就加1,當(dāng)這個對象的年齡大于一定值(默認(rèn)15)就會進(jìn)入老年代。

如果Survior中相同年齡的對象占用的空間大于Survior空間的一半,那么年齡大于或等于這個年齡的對象會直接進(jìn)入老年代,而不用等到達(dá)到特定年齡

當(dāng)進(jìn)行Minor GC時,虛擬機(jī)會檢測之前每次晉升到老年代的平均大小是否大于老年代的剩余空間大小,如果小于,判斷是否開啟了HandlerPRomotionFailure允許擔(dān)保失敗,如果開啟了就只進(jìn)行Minor GC,否則進(jìn)行Full GC。由于使用的之前Minor GC時的平均大小,如果某一次突然大小變大,導(dǎo)致老年代剩余空間不夠,即擔(dān)保失敗,會再進(jìn)行一次Full GC。

finalize

GC時會對活動對象進(jìn)行標(biāo)記,沒有被標(biāo)記的對象就是垃圾對象,但垃圾對象不會直接被清除,垃圾收集器還會判斷是否需要執(zhí)行對象的finalize方法,如果對象沒有覆寫finalize方法或它的finalize已經(jīng)被執(zhí)行過一次,那么是沒有必要執(zhí)行的,否則就認(rèn)為是有必要執(zhí)行的,當(dāng)被判斷為有必要執(zhí)行時,這個對象會被放入一個F-Queue隊列中,由一個后臺的低優(yōu)先級的Finalizer線程執(zhí)行隊列中的對象的finalize方法,對象可以在這個方法中中復(fù)活自己,即重新被其他對象引用,但這個函數(shù)只會被垃圾收集器運(yùn)行一下,第二次回收這個對象時這個函數(shù)不會再被調(diào)用。稍后GC會對F-Queue隊列中的對象執(zhí)行第二次標(biāo)記。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 靖宇县| 枣阳市| 凌云县| 铁岭市| 红原县| 临安市| 教育| 鄂尔多斯市| 津市市| 射洪县| 阜城县| 丽江市| 绥阳县| 北川| 广灵县| 通城县| 大关县| 五原县| 尼玛县| 睢宁县| 台北市| 汝州市| 长顺县| 斗六市| 涡阳县| 玛多县| 阿城市| 哈巴河县| 岳西县| 新化县| 类乌齐县| 昌都县| 海林市| 河曲县| 玛曲县| 清远市| 台南市| 太保市| 枣强县| 深泽县| 威海市|