一文理解JVM虛擬機(jī)(內(nèi)存、垃圾回收、性能優(yōu)化)解決面試中遇到問(wèn)題
一. JVM內(nèi)存區(qū)域的劃分
1.1 java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)
java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)分布圖:
- JVM棧(Java Virtual Machine Stacks): Java中一個(gè)線程就會(huì)相應(yīng)有一個(gè)線程棧與之對(duì)應(yīng),因?yàn)椴煌木€程執(zhí)行邏輯有所不同,因此需要一個(gè)獨(dú)立的線程棧,因此棧存儲(chǔ)的信息都是跟當(dāng)前線程(或程序)相關(guān)信息的,包括局部變量、程序運(yùn)行狀態(tài)、方法返回值、方法出口等等。每一個(gè)方法被調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過(guò)程。
- 堆(Heap): 堆是所有線程共享的,主要是存放對(duì)象實(shí)例和數(shù)組。處于物理上不連續(xù)的內(nèi)存空間,只要邏輯連續(xù)即可
- 方法區(qū)(Method Area): 屬于共享內(nèi)存區(qū)域,存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)
- 常量池(Runtime Constant Pool): 它是方法區(qū)的一部分,用于存放編譯期生成的各種字面量和符號(hào)引用。
- 本地方法棧(Native Method Stacks):
其中,堆(Heap)和JVM棧是程序運(yùn)行的關(guān)鍵,因?yàn)椋?/p>
- 棧是運(yùn)行時(shí)的單位(解決程序的運(yùn)行問(wèn)題,即程序如何執(zhí)行,或者說(shuō)如何處理數(shù)據(jù)),而堆是存儲(chǔ)的單位(解決的是數(shù)據(jù)存儲(chǔ)的問(wèn)題,即數(shù)據(jù)怎么放、放在哪兒)。
- 堆存儲(chǔ)的是對(duì)象。棧存儲(chǔ)的是基本數(shù)據(jù)類型和堆中對(duì)象的引用;(參數(shù)傳遞的值傳遞和引用傳遞)
那為什么要把堆和棧區(qū)分出來(lái)呢?棧中不是也可以存儲(chǔ)數(shù)據(jù)嗎?
- 從軟件設(shè)計(jì)的角度看,棧代表了處理邏輯,而堆代表了數(shù)據(jù),分工明確,處理邏輯更為清晰體現(xiàn)了“分而治之”以及“隔離”的思想。
- 堆與棧的分離,使得堆中的內(nèi)容可以被多個(gè)棧共享(也可以理解為多個(gè)線程訪問(wèn)同一個(gè)對(duì)象)。這樣共享的方式有很多收益:提供了一種有效的數(shù)據(jù)交互方式(如:共享內(nèi)存);堆中的共享常量和緩存可以被所有棧訪問(wèn),節(jié)省了空間。
- 棧因?yàn)檫\(yùn)行時(shí)的需要,比如保存系統(tǒng)運(yùn)行的上下文,需要進(jìn)行地址段的劃分。由于棧只能向上增長(zhǎng),因此就會(huì)限制住棧存儲(chǔ)內(nèi)容的能力。而堆不同,堆中的對(duì)象是可以根據(jù)需要?jiǎng)討B(tài)增長(zhǎng)的,因此棧和堆的拆分,使得動(dòng)態(tài)增長(zhǎng)成為可能,相應(yīng)棧中只需記錄堆中的一個(gè)地址即可。
- 堆和棧的結(jié)合完美體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)。當(dāng)我們將對(duì)象拆開,你會(huì)發(fā)現(xiàn),對(duì)象的屬性即是數(shù)據(jù),存放在堆中;而對(duì)象的行為(方法)即是運(yùn)行邏輯,放在棧中。因此編寫對(duì)象的時(shí)候,其實(shí)即編寫了數(shù)據(jù)結(jié)構(gòu),也編寫的處理數(shù)據(jù)的邏輯。
1.2 堆(Heap)和JVM棧:
1.2.1 堆(Heap)
Java堆是java虛擬機(jī)所管理內(nèi)存中最大的一塊內(nèi)存空間,處于物理上不連續(xù)的內(nèi)存空間,只要邏輯連續(xù)即可,主要用于存放各種類的實(shí)例對(duì)象。該區(qū)域被所有線程共享,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,用來(lái)存放對(duì)象的實(shí)例,幾乎所有的對(duì)象以及數(shù)組都在這里分配內(nèi)存(棧上分配、標(biāo)量替換優(yōu)化技術(shù)的例外)。
在 Java 中,堆被劃分成兩個(gè)不同的區(qū)域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被劃分為三個(gè)區(qū)域:Eden、From Survivor(S0)、To Survivor(S1)。如圖所示:
堆的內(nèi)存布局:
這樣劃分的目的是為了使jvm能夠更好的管理內(nèi)存中的對(duì)象,包括內(nèi)存的分配以及回收。 而新生代按eden和兩個(gè)survivor的分法,是為了
- 有效空間增大,eden+1個(gè)survivor;
- 有利于對(duì)象代的計(jì)算,當(dāng)一個(gè)對(duì)象在S0/S1中達(dá)到設(shè)置的XX:MaxTenuringThreshold值后,會(huì)將其挪到老年代中,即只需掃描其中一個(gè)survivor。如果沒有S0/S1,直接分成兩個(gè)區(qū),該如何計(jì)算對(duì)象經(jīng)過(guò)了多少次GC還沒被釋放。
- 兩個(gè)Survivor區(qū)可解決內(nèi)存碎片化
1.2.2 堆棧相關(guān)的參數(shù)
Note: 每次GC 后會(huì)調(diào)整堆的大小,為了防止動(dòng)態(tài)調(diào)整帶來(lái)的性能損耗,一般設(shè)置-Xms、-Xmx 相等。
新生代的三個(gè)設(shè)置參數(shù):-Xmn,-XX:NewSize,-XX:NewRatio的優(yōu)先級(jí):
1).最高優(yōu)先級(jí): -XX:NewSize=1024m和-XX:MaxNewSize=1024m
2).次高優(yōu)先級(jí): -Xmn1024m (默認(rèn)等效效果是:-XX:NewSize==-XX:MaxNewSize==1024m)
3).最低優(yōu)先級(jí):-XX:NewRatio=2
推薦使用的是-Xmn參數(shù),原因是這個(gè)參數(shù)很簡(jiǎn)潔,相當(dāng)于一次性設(shè)定NewSize和MaxNewSIze,而且兩者相等。
1.3 jvm對(duì)象
1.3.1 創(chuàng)建對(duì)象的方式
各個(gè)方式的實(shí)質(zhì)操作如下:
1.3.2 jvm對(duì)象分配
在虛擬機(jī)層面上創(chuàng)建對(duì)象的步驟:
1.3.3 對(duì)象分配內(nèi)存方式
分配對(duì)象內(nèi)存,有兩種分配方式,指針碰撞和空閑列表:
1)如果內(nèi)存是規(guī)整的,那么虛擬機(jī)將采用的是指針碰撞法(Bump The Pointer)來(lái)為對(duì)象分配內(nèi)存。意思是所有用過(guò)的內(nèi)存在一邊,空閑的內(nèi)存在另外一邊,中間放著一個(gè)指針作為分界點(diǎn)的指示器,分配內(nèi)存就僅僅是把指針向空閑那邊挪動(dòng)一段與對(duì)象大小相等的距離罷了。如果垃圾收集器選擇的是Serial、ParNew這種基于壓縮算法的,虛擬機(jī)采用這種分配方式。一般使用帶有compact(整理)過(guò)程的收集器時(shí),使用指針碰撞。
2)如果內(nèi)存不是規(guī)整的,已使用的內(nèi)存和未使用的內(nèi)存相互交錯(cuò),那么虛擬機(jī)將采用的是空閑列表法來(lái)為對(duì)象分配內(nèi)存。意思是虛擬機(jī)維護(hù)了一個(gè)列表,記錄上哪些內(nèi)存塊是可用的,再分配的時(shí)候從列表中找到一塊足夠大的空間劃分給對(duì)象實(shí)例,并更新列表上的內(nèi)容。這種分配方式成為“空閑列表(Free List)”。
Note: 選擇哪種分配方式由Java堆是否規(guī)整決定,而Java堆是否規(guī)整又由所采用的垃圾收集器是否帶有壓縮整理功能決定。
1.3.4 那什么樣的對(duì)象能夠進(jìn)入老年代(Old)
1.4 內(nèi)存分配與回收策略
對(duì)象優(yōu)先在Eden分配,大多數(shù)情況下,對(duì)象在新生代Eden區(qū)中分配,當(dāng)Eden區(qū)沒有足夠的空間進(jìn)行分配時(shí),虛擬機(jī)將發(fā)起一次Minor GC;虛擬機(jī)提供了-XX:PrintGCDetails參數(shù),發(fā)生垃圾回收時(shí)打印內(nèi)存回收日志,并且在進(jìn)程退出時(shí)輸出當(dāng)前內(nèi)存各區(qū)域的分配情況。
大對(duì)象直接進(jìn)入老年代,所謂的大對(duì)象就是指,需要大量連續(xù)內(nèi)存空間的java對(duì)象,最典型的大對(duì)象就是那種很長(zhǎng)的字符串及數(shù)組。虛擬機(jī)提供了一個(gè)-XX:PretenureSizeThreshold參數(shù),令大于這個(gè)設(shè)置值得對(duì)象直接在老年代中分配(這樣做的目的是避免在Eden區(qū)及兩個(gè)Survivor之間發(fā)生大量的內(nèi)存拷貝)
長(zhǎng)期存活的對(duì)象將直接進(jìn)入老年代,對(duì)象年齡計(jì)數(shù)器。-XX:MaxTenuringThreshold
動(dòng)態(tài)對(duì)象年齡判定,虛擬機(jī)并不總是要求對(duì)象的年齡必須達(dá)到MaxTenuringThreshold才能晉升老年代,如果在Survivor空間中相同年齡所有對(duì)象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代,無(wú)需等到MaxTenuringThreshold中要求的年齡
空間分配擔(dān)保,在發(fā)生Minor GC時(shí)(前),虛擬機(jī)會(huì)檢測(cè)之前每次晉升到老年代的平均大小(因?yàn)楫?dāng)次會(huì)有多少對(duì)象會(huì)存活是無(wú)法確定的,所以取之前的平均值/經(jīng)驗(yàn)值)是否大于老年代的剩余空間大小,如果大于,則改為直接進(jìn)行一次Full GC。如果小于,則查看HandlePromotionFailure設(shè)置是否允許擔(dān)保失敗;如果允許,那只會(huì)進(jìn)行Minor GC;如果不允許,則也要改為進(jìn)行一次Full GC。取平均值進(jìn)行比較其實(shí)仍然是一種動(dòng)態(tài)概率手段,也就是說(shuō)如果某次Minor GC存活后的對(duì)象突增,遠(yuǎn)遠(yuǎn)高于平均值的話,依然會(huì)導(dǎo)致?lián)J?Handle Promotion Failure),這樣會(huì)觸發(fā)Full GC。
2.1 引用二 垃圾回收算法分類
2.2 GC Root的對(duì)象
2.3 標(biāo)記-清除(Mark—Sweep)
被譽(yù)為現(xiàn)代垃圾回收算法的思想基礎(chǔ)。
標(biāo)記-清除算法采用從根集合進(jìn)行掃描,對(duì)存活的對(duì)象對(duì)象標(biāo)記,標(biāo)記完畢后,再掃描整個(gè)空間中未被標(biāo)記的對(duì)象,進(jìn)行回收,如上圖所示。標(biāo)記-清除算法不需要進(jìn)行對(duì)象的移動(dòng),并且僅對(duì)不存活的對(duì)象進(jìn)行處理,在存活對(duì)象比較多的情況下極為高效,但由于標(biāo)記-清除算法直接回收不存活的對(duì)象,因此會(huì)造成內(nèi)存碎片。
2.4 復(fù)制算法(Copying)
該算法的提出是為了克服句柄的開銷和解決堆碎片的垃圾回收。建立在存活對(duì)象少,垃圾對(duì)象多的前提下。此算法每次只處理正在使用中的對(duì)象,因此復(fù)制成本比較小,同時(shí)復(fù)制過(guò)去后還能進(jìn)行相應(yīng)的內(nèi)存整理,不會(huì)出現(xiàn)碎片問(wèn)題。但缺點(diǎn)也是很明顯,就是需要兩倍內(nèi)存空間。
它開始時(shí)把堆分成 一個(gè)對(duì)象 面和多個(gè)空閑面, 程序從對(duì)象面為對(duì)象分配空間,當(dāng)對(duì)象滿了,基于copying算法的垃圾 收集就從根集中掃描活動(dòng)對(duì)象,并將每個(gè)活動(dòng)對(duì)象復(fù)制到空閑面(使得活動(dòng)對(duì)象所占的內(nèi)存之間沒有空閑洞),這樣空閑面變成了對(duì)象面,原來(lái)的對(duì)象面變成了空閑面,程序會(huì)在新的對(duì)象面中分配內(nèi)存。一種典型的基于coping算法的垃圾回收是stop-and-copy算法,它將堆分成對(duì)象面和空閑區(qū)域面,在對(duì)象面與空閑區(qū)域面的切換過(guò)程中,程序暫停執(zhí)行。
2.5 標(biāo)記-整理(或標(biāo)記-壓縮算法,Mark-Compact,又或者叫標(biāo)記清除壓縮MarkSweepCompact)
此算法是結(jié)合了“標(biāo)記-清除”和“復(fù)制算法”兩個(gè)算法的優(yōu)點(diǎn)。避免了“標(biāo)記-清除”的碎片問(wèn)題,同時(shí)也避免了“復(fù)制”算法的空間問(wèn)題。
標(biāo)記-整理算法采用標(biāo)記-清除算法一樣的方式進(jìn)行對(duì)象的標(biāo)記,但在清除時(shí)不同,在回收不存活的對(duì)象占用的空間后,會(huì)將所有的存活對(duì)象往左端空閑空間移動(dòng),并更新對(duì)應(yīng)的指針。標(biāo)記-整理算法是在標(biāo)記-清除算法的基礎(chǔ)上,又進(jìn)行了對(duì)象的移動(dòng),因此成本更高,但是卻解決了內(nèi)存碎片的問(wèn)題。在基于Compacting算法的收集器的實(shí)現(xiàn)中,一般增加句柄和句柄表。
2.6 分代回收策略(Generational Collecting)
基于這樣的事實(shí):不同的對(duì)象的生命周期是不一樣的。因此,不同生命周期的對(duì)象可以采取不同的回收算法,以便提高回收效率。
新生代由于其對(duì)象存活時(shí)間短,且需要經(jīng)常gc,因此采用效率較高的復(fù)制算法,其將內(nèi)存區(qū)分為一個(gè)eden區(qū)和兩個(gè)suvivor區(qū),默認(rèn)eden區(qū)和survivor區(qū)的比例是8:1,分配內(nèi)存時(shí)先分配eden區(qū),當(dāng)eden區(qū)滿時(shí),使用復(fù)制算法進(jìn)行g(shù)c,將存活對(duì)象復(fù)制到一個(gè)survivor區(qū),當(dāng)一個(gè)survivor區(qū)滿時(shí),將其存活對(duì)象復(fù)制到另一個(gè)區(qū)中,當(dāng)對(duì)象存活時(shí)間大于某一閾值時(shí),將其放入老年代。老年代和永久代因?yàn)槠浯婊顚?duì)象時(shí)間長(zhǎng),因此使用標(biāo)記清除或標(biāo)記整理算法
總結(jié):
新生代:復(fù)制算法(新生代回收的頻率很高,每次回收的耗時(shí)很短,為了支持高頻率的新生代回收,虛擬機(jī)可能使用一種叫做卡表(Card Table)的數(shù)據(jù)結(jié)構(gòu),卡表為一個(gè)比特位集合,每個(gè)比特位可以用來(lái)表示老年代的某一區(qū)域中的所有對(duì)象是否持有新生代對(duì),
2.7 垃圾回收器
垃圾回收器的任務(wù)是識(shí)別和回收垃圾對(duì)象進(jìn)行內(nèi)存清理,不同代可使用不同的收集器:
- 新生代收集器使用的收集器:Serial、ParNew、Parallel Scavenge;
- 老年代收集器使用的收集器:Serial Old(MSC)、Parallel Old、CMS。
總結(jié):
- Serial old和新生代的所有回收器都能搭配;也可以作為CMS回收器的備用回收器;
- CMS只能和新生代的Serial和ParNew搭配,而且ParNew是CMS默認(rèn)的新生代回收器;
- 并行(Parallel):指多條垃圾收集線程并行工作,但此時(shí)用戶線程仍然處于等待狀態(tài)
- 并發(fā)(Concurrent):指用戶線程和垃圾收集線程同時(shí)執(zhí)行(但不一定是并行的,可能是交替執(zhí)行),用戶程序繼續(xù)運(yùn)行,而垃圾收集程序運(yùn)行在另外的CPU上。
三. GC的執(zhí)行機(jī)制
Java 中的堆(deap) 也是 GC 收集垃圾的主要區(qū)域。由于對(duì)象進(jìn)行了分代處理,因此垃圾回收區(qū)域、時(shí)間也不一樣。GC有兩種類型:Scavenge GC(Minor GC)和Full GC(Major GC):
- Scavenge GC(Minor GC): 一般情況下,當(dāng)新對(duì)象生成(age=0),并且在Eden申請(qǐng)空間失敗時(shí),就會(huì)觸發(fā)Scavenge GC,對(duì)Eden區(qū)域進(jìn)行GC,清除非存活對(duì)象,并且把尚且存活的對(duì)象移動(dòng)到Survivor區(qū)(age+1)。然后整理(其實(shí)是復(fù)制過(guò)去就順便整理了)Survivor的兩個(gè)區(qū)。這種方式的GC是對(duì)年輕代的Eden區(qū)進(jìn)行,不會(huì)影響到年老代。因?yàn)榇蟛糠謱?duì)象都是從Eden區(qū)開始的,同時(shí)Eden區(qū)不會(huì)分配的很大,所以Eden區(qū)的GC會(huì)頻繁進(jìn)行。因而,一般在這里需要使用速度快、效率高的算法(即復(fù)制-清理算法),使Eden去能盡快空閑出來(lái)。Java 中的大部分對(duì)象通常不需長(zhǎng)久存活,具有朝生夕滅的性質(zhì)。
- Full GC:對(duì)整個(gè)堆進(jìn)行整理,包括Young、Tenured和Perm。Full GC因?yàn)樾枰獙?duì)整個(gè)對(duì)進(jìn)行回收,所以比Scavenge GC要慢,因此應(yīng)該盡可能減少Full GC的次數(shù)。在對(duì)JVM調(diào)優(yōu)的過(guò)程中,很大一部分工作就是對(duì)于FullGC的調(diào)節(jié)。
3.1 觸發(fā)Full GC執(zhí)行的場(chǎng)景
3.2 Young GC觸發(fā)條件
3.3 新生對(duì)象GC收回流程
基于大多數(shù)新生對(duì)象都會(huì)在GC中被收回的假設(shè)。新生代的GC 使用復(fù)制算法,(將年輕代分為3部分,主要是為了生命周期短的對(duì)象盡量留在年輕代。老年代主要存放生命周期比較長(zhǎng)的對(duì)象,比如緩存)。可能經(jīng)歷過(guò)程:
- 對(duì)象創(chuàng)建時(shí),一般在Eden區(qū)完成內(nèi)存分配(有特殊);
- 當(dāng)Eden區(qū)滿了,再創(chuàng)建對(duì)象,會(huì)因?yàn)樯暾?qǐng)不到空間,觸發(fā)minorGC,進(jìn)行young(eden+1survivor)區(qū)的垃圾回收;
- minorGC時(shí),Eden和survivor A不能被GC回收且年齡沒有達(dá)到閾值(tenuring threshold)的對(duì)象,會(huì)被放入survivor B,始終保證一個(gè)survivor是空的;
- 當(dāng)做第3步的時(shí)候,如果發(fā)現(xiàn)survivor滿了,將這些對(duì)象copy到old區(qū)(分配擔(dān)保機(jī)制);或者survivor并沒有滿,但是有些對(duì)象已經(jīng)足夠Old,也被放入Old區(qū) XX:MaxTenuringThreshold;(回顧下對(duì)象進(jìn)入老年代的情況)
- 直接清空eden和survivor A;
- 當(dāng)Old區(qū)被放滿的之后,進(jìn)行fullGC。
3.4 GC日志
GC日志相關(guān)參數(shù):
- -XX:+PrintGC:輸出GC日志
- -XX:+PrintGCDetails:輸出GC的詳細(xì)日志
- -XX:+PrintGCTimeStamps:輸出GC的時(shí)間戳(以基準(zhǔn)時(shí)間的形式)
- -XX:+PrintGCApplicationStoppedTime:打印垃圾回收期間程序暫停的時(shí)間
- -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中斷的執(zhí)行時(shí)間
- -XX:+PrintHeapAtGC:在進(jìn)行GC的前后打印出堆的信息
- -XX:+PrintTLAB:查看TLAB空間的使用情況
- -XX:PrintTenuingDistribution:查看每次minor GC后新的存活周期的閾值
- -XX:PrintReferenceFC:用來(lái)跟蹤系統(tǒng)內(nèi)的(softReference)軟引用,(weadReference)弱引用,(phantomReference)虛引用,顯示引用過(guò)程
案例分析:
-XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime一起使用
Application time: 0.3440086 seconds Total time for which application threads were stopped: 0.0620105 seconds Application time: 0.2100691 seconds Total time for which application threads were stopped: 0.0890223 seconds
得知應(yīng)用程序在前344毫秒中是在處理實(shí)際工作的,然后將所有線程暫停了62毫秒,緊接著又工作了210ms,然后又暫停了89ms。
2796146K->2049K(1784832K)] 4171400K->2049K(3171840K), [Metaspace: 3134K->3134K(1056768K)], 0.0571841 secs] [Times: user=0.02 sys=0.04, real=0.06 secs]Total time for which application threads were stopped: 0.0572646 seconds, Stopping threads took: 0.0000088 seconds
應(yīng)用線程被強(qiáng)制暫停了57ms來(lái)進(jìn)行垃圾回收。其中又有8ms是用來(lái)等待所有的應(yīng)用線程都到達(dá)安全點(diǎn)。
只要設(shè)置-XX:+PrintGCDetails 就會(huì)自動(dòng)帶上-verbose:gc和-XX:+PrintGC
33.125: [GC [DefNew: 3324K->152K(3712K), 0.0025925 secs] 3324K->152K(11904K), 0.0031680 secs]100.667: [Full GC [Tenured: 0K->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm : 2999K->2999K(21248K)], 0.0150007 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
- 最前面的數(shù)字“33.125:”和“100.667:”代表了GC發(fā)生的時(shí)間,這個(gè)數(shù)字的含義是從Java虛擬機(jī)啟動(dòng)以來(lái)經(jīng)過(guò)的秒數(shù)。
- GC日志開頭的“[GC”和“[Full GC”說(shuō)明了這次垃圾收集的停頓類型,而不是用來(lái)區(qū)分新生代GC還是老年代GC的。如果有“Full”,說(shuō)明這次GC是發(fā)生了Stop-The-World的。
- 接下來(lái)的“[DefNew”、“[Tenured”、“[Perm”表示GC發(fā)生的區(qū)域,這里顯示的區(qū)域名稱與使用的GC收集器是密切相關(guān)的,例如上面樣例所使用的Serial收集器中的新生代名為“Default New Generation”,所以顯示的是“[DefNew”。如果是ParNew收集器,新生代名稱就會(huì)變?yōu)?ldquo;[ParNew”,意為“Parallel New Generation”。如果采用Parallel Scavenge收集器,那它配套的新生代稱為“PSYoungGen”,老年代和永久代同理,名稱也是由收集器決定的。
- 后面方括號(hào)內(nèi)部的“3324K->152K(3712K)”含義是“GC前該內(nèi)存區(qū)域已使用容量-> GC后該內(nèi)存區(qū)域已使用容量 (該內(nèi)存區(qū)域總?cè)萘?”。而在方括號(hào)之外的“3324K->152K(11904K)”表示“GC前Java堆已使用容量 -> GC后Java堆已使用容量 (Java堆總?cè)萘?”。
- 再往后,“0.0025925 secs”表示該內(nèi)存區(qū)域GC所占用的時(shí)間,單位是秒。有的收集器會(huì)給出更具體的時(shí)間數(shù)據(jù)
- [Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000288 secs] 新生代收集器ParNew的日志也會(huì)出現(xiàn)“[Full GC”(這一般是因?yàn)槌霈F(xiàn)了分配擔(dān)保失敗之類的問(wèn)題,所以才導(dǎo)致STW)。如果是調(diào)用System.gc()方法所觸發(fā)的收集,那么在這里將顯示“[Full GC (System)”。
3.5 減少GC開銷的措施
從代碼上:
從JVM參數(shù)上調(diào)優(yōu)上:
3.6 內(nèi)存溢出分類
四. 總結(jié)-JVM調(diào)優(yōu)相關(guān)
4.1 調(diào)優(yōu)目的
4.2 JVM性能調(diào)優(yōu)所處的層次
4.3 JVM調(diào)優(yōu)流程
4.4 性能監(jiān)控工具
調(diào)優(yōu)的最終目的都是為了令應(yīng)用程序使用最小的硬件消耗來(lái)承載更大的吞吐。jvm的調(diào)優(yōu)也不例外,jvm調(diào)優(yōu)主要是針對(duì)垃圾收集器的收集性能優(yōu)化,令運(yùn)行在虛擬機(jī)上的應(yīng)用能夠使用更少的內(nèi)存以及延遲獲取更大的吞吐量。