垃圾回收在哪一章java_Java垃圾回收机制
Java 內(nèi)存運(yùn)行時(shí)區(qū)域中的程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧隨線程而生滅,棧中的棧幀隨著方法的進(jìn)入和退出而有條不紊地執(zhí)行著出棧和入棧操作。每一個(gè)棧幀中分配多少內(nèi)存基本上是在類結(jié)構(gòu)確定下來時(shí)就已知的(盡管在運(yùn)行期會(huì)由 JIT 編譯器進(jìn)行一些優(yōu)化),因此這幾個(gè)區(qū)域的內(nèi)存分配和回收都具備確定性,不需要過多考慮回收的問題,因?yàn)榉椒ńY(jié)束或者線程結(jié)束時(shí),內(nèi)存自然就跟隨著回收了。
而 Java 堆不一樣,一個(gè)接口中的多個(gè)實(shí)現(xiàn)類需要的內(nèi)存可能不一樣,一個(gè)方法中的多個(gè)分支需要的內(nèi)存也可能不一樣,我們只有在程序處于運(yùn)行期間時(shí)才能知道會(huì)創(chuàng)建哪些對象,這部分內(nèi)存的分配和回收都是動(dòng)態(tài)的,垃圾收集器所關(guān)注的是這部分內(nèi)存。
自動(dòng)垃圾收集
自動(dòng)垃圾收集是查看堆內(nèi)存,識(shí)別正在使用那些對象,那些對象未被刪除,刪除未被使用對象的過程。使用中對象或引用的對象意味著程序的某些部分任然維護(hù)指向該對象的指針。程序的任何部分都不再引用未使用的對象或未引用的對象,則可以回收未引用對象的內(nèi)存。在C語言中,內(nèi)存的分配和釋放是手動(dòng)的過程,在Java語言中內(nèi)存的分配和回收是由垃圾收集器自動(dòng)處理的。
而在自動(dòng)垃圾收集中如何確定那些內(nèi)存需要被回收,通常來說第一步就是標(biāo)記,利用引用計(jì)數(shù),可達(dá)性分析等來標(biāo)記那些內(nèi)存正在使用,那些內(nèi)存不在使用。
引用計(jì)數(shù)法
引用計(jì)數(shù)法主要是通過給對象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)一個(gè)地方引用它時(shí),計(jì)數(shù)器的值就加1,當(dāng)引用失效時(shí),計(jì)數(shù)器的值就減1,當(dāng)計(jì)數(shù)器的值為0時(shí),對象就是不可能被使用的,可以對其進(jìn)行垃圾回收。引用計(jì)數(shù)法的實(shí)現(xiàn)簡單,效率也比較高,但是它很難解決對象之間循環(huán)引用的問題。
可達(dá)性分析算法
可達(dá)性分析算法,也稱為根搜索算法,這個(gè)算法的基本思路就是通過一系列的名為“GC Roots”的對象為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對象到“GC Roots”沒有任何引用鏈相連,則證明對象是不可用的,可以對其進(jìn)行垃圾回收。
簡單來說,將對象及其引用關(guān)系看作一個(gè)圖,選定活動(dòng)的對象作為“GC Roots”,然后跟蹤引用鏈條,如果一個(gè)對象和”GC Roots“之間不可達(dá),也就是不存在引用,即可認(rèn)為是可回收對象。
引用類型和可達(dá)性級(jí)別
引用類型:
強(qiáng)引用(Strong Reference):最常見的普通引用,只要還有強(qiáng)引用指向一個(gè)對象,就不會(huì)回收
軟引用(Soft Reference):JVM認(rèn)為內(nèi)存不足阿時(shí)候,才會(huì)去試圖回收軟引用指向的對象(緩存場景)
弱引用(Weak Reference):雖然是引用,但隨時(shí)有可能被回收掉
虛引用(Phantom Reference):不能通過它訪問對象,提供對象被finalize以后,執(zhí)行指定邏輯的機(jī)制。
可達(dá)性級(jí)別:
強(qiáng)可達(dá)(Strongly Reachable):一個(gè)對象可以有一個(gè)或多個(gè)線程可以不通過各種引用訪問到的情況
軟可達(dá)(Softly Reachable):只能通過軟引用才能訪問到的狀態(tài)
弱引用(Weakly Reachable):只能通過弱引用訪問時(shí)的狀態(tài),當(dāng)弱引用被清除的時(shí)候,就符合銷毀條件
幻像可達(dá)(Phantom Reachable):不存在其他引用,并且finalize過了,只有幻像引用指向這個(gè)對象
不可達(dá)(Unreachable):意味著對象可以被清除了
垃圾收集算法
目前主流廣泛使用的垃圾收集算法,主要有標(biāo)記-清除算法(Mark-Sweep),復(fù)制算法(Coping)以及標(biāo)記-整理算法(Mark-Compact)。
標(biāo)記-清除算法:首先識(shí)別出所有要回收的對象,然后進(jìn)行清除。標(biāo)記,清除的過程效率有限,存在內(nèi)存碎片化的問題,不適合特別大的堆。其他收集算法基本都是基于標(biāo)記-清除的思路進(jìn)行改進(jìn)。
復(fù)制算法:劃分兩塊同等大小的區(qū)域,收集時(shí)將活著的對象復(fù)制到另一塊區(qū)域。復(fù)制過程中將對象順序放置,就可以避免內(nèi)存碎片化。但是復(fù)制加上預(yù)留內(nèi)存有一定的浪費(fèi)
標(biāo)記-整理算法:類似于標(biāo)記-清除,但為避免內(nèi)存碎片化,它會(huì)在清理過程中將對象移動(dòng),以確保移動(dòng)后的對象占用連續(xù)的內(nèi)存
分代收集
根據(jù)對象的存活周期,將內(nèi)存劃分為幾個(gè)區(qū)域,不同區(qū)域采用合適的垃圾收集算法。目前主流的JVM一般將堆內(nèi)存分為新生代和老年代(大小比列為1:2),而新生代又被分為了eden、from survivor、to survivor(大小比列為8:1:1)。在新生代中,每次垃圾收集時(shí)都發(fā)現(xiàn)有大量對象死去,只有少量存活,那么就可以選用復(fù)制算法,只需付出少量對象的復(fù)制成本就可以完成收集。在老年代中,對象存活率高,就可以使用標(biāo)記-清除,標(biāo)記-整理算法。
新生代幾乎是所有JAVA對象出生的地方,JAVA對象申請的內(nèi)存和存放都是在這個(gè)地方,JVM每次只會(huì)使用新生代中的eden和其中一塊survivor來為對象服務(wù),所以無論什么時(shí)候,都會(huì)有一塊survivor空間空閑。當(dāng)對象經(jīng)過一次minor gc后仍然存活,并且能夠被另外一塊survivor所容納,則使用復(fù)制算法將這些仍然存活的對象復(fù)制到另外一塊survior區(qū)域中,然后清理掉eden和之前使用的survivor區(qū)域,并將這些存活的對象年齡+1,以后對象在survivor中每熬過一次minor gc則年齡增加1,當(dāng)年齡達(dá)到某個(gè)值時(shí)(默認(rèn)15,通過設(shè)置參數(shù)-XX:MaxTenuringThreshold來設(shè)置),這些對象就會(huì)進(jìn)入老年代。當(dāng)然,對于一些較大的對象可以直接進(jìn)入老年代,可以根據(jù)-XX:+PretenureSizeThreshold設(shè)置大對象進(jìn)入老年代的閾值。
新生代采用復(fù)制算法:
老年代使用標(biāo)記-整理算法:
垃圾收集器
垃圾收集算法只是內(nèi)存回收的理論方法,垃圾收集器才是內(nèi)存回收的具體實(shí)現(xiàn)。Java虛擬機(jī)規(guī)范中對垃圾收集器的實(shí)現(xiàn)沒有具體的規(guī)定,不同廠商,不同版本的垃圾收集器可能會(huì)差別很大。目前常見的垃圾收集器主要有Serial收集器,ParNew收集器,Parallel Scavenge收集器,Serial Old收集器,Parallel Old收集器,CMS收集器,G1收集器。這些垃圾收集器各有優(yōu)劣,一般都是組合在一起使用,下圖展示了在新生代和老年代可用的垃圾收集器組合:
Serial收集器
Serial收集器是一個(gè)串行收集器,使用單個(gè)線程來執(zhí)行所有垃圾收集工作,適合單處理器機(jī)器,GC在工作的時(shí)候?qū)和F渌械墓ぷ骶€程,即”Stop The World“。Serial收集器是一個(gè)新生代的單線程收集器,它使用復(fù)制算法,是虛擬機(jī)在client模式下的默認(rèn)新生代收集器,可以通過設(shè)置參數(shù)-XX:+UseSerialGC來使用。
ParNew收集器
ParNew收集器可以理解為串行收集器的多線程版本,其整體算法和Serial比較相似,除了使用多線程進(jìn)行垃圾回收,其他的基本和Serial收集器一樣。ParNew收集器是虛擬機(jī)在server模式下的默認(rèn)新生代收集器,可以通過設(shè)置參數(shù)-XX:+UseParNewGC來使用。默認(rèn)情況下它開啟的線程數(shù)和CPU數(shù)量相同,也可以通過設(shè)置參數(shù)-XX:ParallelGCThreads來配置垃圾收集的線程數(shù)。
Parallel Scavenge收集器
Parallel Scavenge收集器也是一個(gè)新生代的并行垃圾收集器,使用的也是復(fù)制算法。Parallel Scavenge收集器的目標(biāo)是達(dá)到一個(gè)可控制的吞吐量。吞吐量就是CPU運(yùn)行用戶代碼的時(shí)間與CPU消耗的總時(shí)間的比值,即吞吐量=運(yùn)行用戶代碼時(shí)間/(運(yùn)行用戶代碼時(shí)間+垃圾收集時(shí)間)。Parallel Scavenge收集器提供-XX:MaxGCPauseMillis來控制最大垃圾收集停頓時(shí)間和-XX:GCTimeRatio來直接設(shè)置吞吐量的大小。
Serial Old收集器
Serial Old收集器是Serial收集器的在老年代使用的版本,它采用了標(biāo)記-整理算法,可以通過設(shè)置參數(shù)-XX:+UseSerialOldGC來使用。
Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線程和標(biāo)記-整理算法,可以通過設(shè)置參數(shù)-XX:+UseParallelOldGC來使用。
CMS收集器
CMS收集器是一個(gè)并發(fā)收集器,CMS即Concurrent Mark Swap,主要用于老年代,使用標(biāo)記-清除算法,可以通過設(shè)置參數(shù)-XX:+UseConcMarkSweepGC來使用。CMS收集器可以并行的執(zhí)行用戶程序和垃圾回收,這樣就可以減少回收的停頓時(shí)間。CMS收集器設(shè)計(jì)的主要目的就是為了減少回收停頓時(shí)間,目前很多的Java應(yīng)用都集中在互聯(lián)網(wǎng)網(wǎng)站或B/S系統(tǒng)服務(wù)端,這類應(yīng)用尤其重視服務(wù)的響應(yīng)速度,希望系統(tǒng)停頓時(shí)間最短,CMS收集器非常符合這類應(yīng)用的要求。當(dāng)然,CMS收集器也有自己的缺點(diǎn),它會(huì)占用更多的CPU資源,并和用戶線程爭搶,同時(shí)由于采用標(biāo)記-清除算法,存在著內(nèi)存碎片化的問題,長時(shí)間運(yùn)行等情況下可能發(fā)full gc導(dǎo)致惡劣的停頓。
CMS收集器垃圾收集的整個(gè)過程有4個(gè)步驟,初始標(biāo)記,并發(fā)標(biāo)記,重寫標(biāo)記以及并發(fā)清除。其中初始標(biāo)記和重寫標(biāo)記任然需要”Stop The World”,但是速度很快,整個(gè)過程中耗時(shí)的操作在并發(fā)標(biāo)記和并發(fā)清除階段,在這個(gè)過程中,收集器線程都可以和用戶線程一起工作。
G1收集器
G1(Garage First)收集器是當(dāng)前垃圾收集器技術(shù)最前沿的成果,在JDK7中開始使用(可以通過配置-XX:+UseG1GC使用),從JDK9開始G1已經(jīng)成為JVM默認(rèn)的垃圾收集器。G1垃圾收集器也是以關(guān)注延遲為目標(biāo)、服務(wù)器端應(yīng)用的垃圾收集器,其目標(biāo)就是取代CMS垃圾收集器。
G1采用了分區(qū)(Region)的思路,將整個(gè)堆空間分成若干個(gè)大小相等的內(nèi)存區(qū)域,每次分配對象空間將逐段地使用內(nèi)存,這樣最大的好處就是化整為零,避免全內(nèi)存掃描,只需要按照區(qū)域來進(jìn)行掃描即可。啟動(dòng)時(shí)可以通過參數(shù)-XX:G1HeapRegionSize=n可指定分區(qū)大小(1MB~32MB,且必須是2的冪),默認(rèn)將整堆劃分為2048個(gè)分區(qū)。在堆的使用上,整個(gè)內(nèi)存分區(qū)不存在物理上的年輕代和老年代的區(qū)別,也不需要完全獨(dú)立的 Survivor to space 堆做復(fù)制準(zhǔn)備。G1 只有邏輯上的分代概念,或者說每個(gè)分區(qū)都可能隨 G1 的運(yùn)行在不同代之間前后切換。
G1收集器整體采用標(biāo)記-整理算法,局部是通過是通過復(fù)制算法,不會(huì)產(chǎn)生內(nèi)存碎片,能充分利用多 CPU、多核環(huán)境硬件優(yōu)勢,盡量縮短”Stop The World”的時(shí)間
下圖左側(cè)為G1收集器的內(nèi)存劃分概圖,紅色為新生代(沒有S的為eden區(qū)域,有S的為survivor區(qū)域),藍(lán)色為老年代(帶有H的表示humongous ,存放humongous objects,即大于等于region一半的對象)。右側(cè)為G1收集器的垃圾收集環(huán)圖,G1的垃圾收集在層次上可以分為兩個(gè)階段,young-only階段和Space-reclamation階段,在young-only階段又分為Initial Mark ,Remark,Cleanup。
?
總結(jié)
以上是生活随笔為你收集整理的垃圾回收在哪一章java_Java垃圾回收机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 编辑我的世界_Editing
- 下一篇: java outofmemory jsp