JVM內(nèi)存分區(qū)及GC知識點(diǎn)是什么,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了張家界免費(fèi)建站歡迎大家使用!
本地方法棧:native方法調(diào)用時(shí)的方法調(diào)用棧,存儲(chǔ)本地棧幀
虛擬機(jī)方法棧:Java的棧,每個(gè)線程有一個(gè)線程調(diào)用棧,棧的元素是棧幀。棧幀包括:局部變量表、操作數(shù)棧、指向堆中對象的引用、返回地址、附加信息。每個(gè)方法調(diào)用時(shí),回向當(dāng)前指向的線程棧頂部壓入一個(gè)棧幀,棧幀的大小是固定的,虛擬機(jī)通過解析.class文件可以得知。
堆:堆是所有Java線程共享的一個(gè)內(nèi)存區(qū)域,用于分配對象。
方法區(qū):存儲(chǔ)類的信息(類名、方法信息、字段信息)、靜態(tài)變量、常量池。
程序計(jì)數(shù)器:用于記錄下一條要執(zhí)行的指令,每個(gè)線程都有自己的程序計(jì)數(shù)器,配合線程棧用于在線程調(diào)度時(shí)的線程上下文切換。執(zhí)行本地方法時(shí)程序計(jì)數(shù)器中沒有值或?yàn)閡ndefined。
1.8之前,在HotSpot中堆內(nèi)存分為新生代、老年代、永久代。永久代就是方法區(qū)的實(shí)現(xiàn),占用一部分堆內(nèi)存,但永久代不參與垃圾回收。 1.8及置換,HotSpot將堆內(nèi)存分為新生代、老年代。用元數(shù)據(jù)區(qū)實(shí)現(xiàn)方法區(qū),且元數(shù)據(jù)區(qū)占用堆外內(nèi)存。
引用計(jì)數(shù):每個(gè)對象引用被持有時(shí),引用計(jì)數(shù)+1。引用賦值為null或銷毀時(shí)引用計(jì)數(shù)-1。引用計(jì)數(shù)為0說明沒有再被使用,可以回收。無法解決循環(huán)引用問題。
標(biāo)記-清除算法:第一個(gè)階段標(biāo)記,將存活的對象標(biāo)記出來;第二個(gè)階段是清除,將死亡對象占用的內(nèi)存回收利用。
標(biāo)記-整理算法:第一個(gè)節(jié)點(diǎn)標(biāo)記,標(biāo)記處存貨的對象;第二個(gè)階段整理,將存活的對象整理放到另一處空間中去,然后把當(dāng)前空間的內(nèi)存全部回收。
復(fù)制算法:每次只利用內(nèi)存的一半,當(dāng)內(nèi)存滿時(shí),將存貨對象復(fù)制到另一半中去,這一半內(nèi)存全部回收。
垃圾回收算法并沒有最好的一種,為了達(dá)到降低整體GC時(shí)間的目的,一般是采用對內(nèi)存分代進(jìn)行垃圾回收,每個(gè)代采用不同的回收算法。
新生代 新生代與老年代內(nèi)存占比默認(rèn)為1:2。 新生代又可分為Eden區(qū)、Survivor0、Survivor1區(qū),默認(rèn)占用新生代內(nèi)存比例為8:1:1。
老年代 老年代是一大塊連續(xù)內(nèi)存,沒有再細(xì)分。
MinorGC,也叫做Young GC,YGC, 是發(fā)生在新生代的GC,當(dāng)Eden區(qū)滿時(shí)觸發(fā),HotSpot中新生代均GC采用復(fù)制算法實(shí)現(xiàn)。 新分配的對象一般是在Eden區(qū),除非滿足條件時(shí),對象會(huì)直接分配到堆上。Eden區(qū)滿之后會(huì)將Eden存活對象拷貝到survivor0區(qū)。當(dāng)survivor0內(nèi)存不足時(shí),將survivor0中存活的對象拷貝到survivor1區(qū),并回收survivor0區(qū),然后交換survivor0和survivor1的名稱。一般也叫from和to。 每次從from到to的拷貝,都會(huì)記錄對象的年齡+1,當(dāng)對象年齡達(dá)到一個(gè)設(shè)定的值后(默認(rèn)15),對象會(huì)被分配到老年代。 如果從from向to的拷貝過程中發(fā)現(xiàn)to內(nèi)存不夠用,也會(huì)將對象轉(zhuǎn)存到老年代。
直接老年代分配內(nèi)存的情況:
對象所需內(nèi)存大小超過Eden區(qū)大小,所有收集器都支持。
Eden區(qū)內(nèi)存不足,且對象所需內(nèi)存大小超過Eden區(qū)一半,直接分配到老年代,且不觸發(fā)MinorGC。使用ParallelScavenge時(shí)支持。
對象大小超過XX:PretenureSizeThreshold設(shè)置時(shí),直接進(jìn)入老年代分配。Serial、ParNew、CMS收集器支持。
FullGC FullGC是發(fā)生在老年代的GC,觸發(fā)時(shí)機(jī)有:
調(diào)用System.gc()時(shí),系統(tǒng)會(huì)建議執(zhí)行GC,但不是立即執(zhí)行。
從新生代晉升到老年代的對象所需內(nèi)存大于老年代可用內(nèi)存時(shí)。
GC吞吐量 = 用戶代碼執(zhí)行時(shí)間 / (用戶代碼執(zhí)行時(shí)間 + GC時(shí)間)
jdk1.7和1.8默認(rèn)采用ParallelGC,也就是Parallel Scavenge(新生代)+Parallel Old(老年代)GC。 jdk9采用G1垃圾收集器。
其他的垃圾收集器還有CMS、ParaNew、Serial等 查看java默認(rèn)垃圾收集器命令:
java -XX:+PrintCommandLineFlags -version -XX:+UseParallelGC 表示使用Parallel Scavenge + Parallel Old -XX:+UseConcMarkSweepGC 在啟動(dòng)應(yīng)用加上這個(gè)參數(shù)表示使用CMS垃圾收集器 -XX:+UseG1GC 在啟動(dòng)應(yīng)用時(shí)添加這個(gè)參數(shù)表示使用G1垃圾收集器,jdk8中支持開啟
使用單線程進(jìn)行垃圾回收,GC時(shí)停止用于線程工作。單CPU環(huán)境下表現(xiàn)好,因?yàn)闆]有GC線程間的交互。 Serial用于新生代,復(fù)制算法。Serial Old用于老年代,基于標(biāo)記-整理
Serial的多線程版本,采用復(fù)制算法。在單CPU時(shí)不如Serial,多CPU效果較好。 ParNew用于新生代。
Parallel Scavenge采用復(fù)制算法。算法目的是提高吞吐量,降低GC時(shí)間(但可能提升GC次數(shù)),讓用戶代碼得到更多執(zhí)行時(shí)機(jī)。 Parallel代表并行,即多個(gè)GC線程同時(shí)進(jìn)行,但還是會(huì)暫停用戶線程,在GC完成后用戶線程才繼續(xù)執(zhí)行。 相比較于ParNew收集器,可以添加啟動(dòng)參數(shù)XX+UseAdaptiveSizePolicy,添加參數(shù)后可以不用設(shè)置Eden和Survivor區(qū)比例,也不用設(shè)置晉升老年代對象年齡等細(xì)節(jié)參數(shù),該算法會(huì)自動(dòng)根據(jù)系統(tǒng)運(yùn)行情況動(dòng)態(tài)調(diào)節(jié)參數(shù)。
Parallel Old是Parallel Scavenge的老年代版本,采用標(biāo)記-整理算法??梢圆l(fā)GC,整個(gè)GC過程是暫停用戶線程執(zhí)行的。
CMS全名Concurrent Mark Sweep,并發(fā)標(biāo)記-回收垃圾收集器。是老年代的GC處理器。 CMS分為四個(gè)步驟:
初始標(biāo)記:僅標(biāo)記GCRoots和新生代能夠直接引用到的老年代對象,速度較快,觸發(fā)STW。
并發(fā)標(biāo)記:此階段GC標(biāo)記線程與用戶線程同時(shí)執(zhí)行,遍歷初始標(biāo)記的對象,并遞歸標(biāo)記這些對象引用的全部對象,這個(gè)過程比較慢,但是不觸發(fā)STW。 因?yàn)檫@個(gè)階段是并發(fā)標(biāo)記,可能發(fā)生 對象從新生代晉升到老年代、直接在老年代分配對象、老年代引用對象關(guān)系發(fā)生變化、新生代對老年代對象引用發(fā)生變化 等現(xiàn)象,對于這些對象都是要重新標(biāo)記的。 做法是將這些對象所在的Card Table中的位設(shè)置為dirty,把并發(fā)標(biāo)記階段新產(chǎn)生的對象和對象引用關(guān)系的變化記錄下來(記錄到Mod-Union Table)。
Card Table:將老年代內(nèi)存分為相等大小的CardPage,每個(gè)CardPage用一個(gè)二進(jìn)制位表示其內(nèi)部的對象在并發(fā)標(biāo)記階段是否發(fā)生了引用變化,這個(gè)二進(jìn)制位數(shù)組就是CardTable。 Mod-Union Table:是一個(gè)和CardTable類似的結(jié)構(gòu); 3. 并發(fā)預(yù)清理:從Mod-Union Table中找到并發(fā)標(biāo)記階段標(biāo)記為dirty的內(nèi)存區(qū)域,重新標(biāo)記這些引用關(guān)系發(fā)生過變化的對象??梢酝ㄟ^參數(shù)CMSPrecleaningEnabled來關(guān)閉這個(gè)階段,默認(rèn)開啟的。
4. 并發(fā)可中斷預(yù)清理:循環(huán)處理From和To區(qū)對象,標(biāo)記可達(dá)的老年代對象;并且循環(huán)處理DirtyCard的標(biāo)記,不觸發(fā)STW。循環(huán)的退出條件有三種
循環(huán)次數(shù)超過CMSMaxAbortablePrecleanLoops設(shè)置,默認(rèn)0,沒有次數(shù)限制;
循環(huán)時(shí)間超過CMSMaxAbortablePrecleanTime設(shè)置,默認(rèn)5s,超過會(huì)退出;
并發(fā)預(yù)清理時(shí)Eden使用率低于10%,而某一次循環(huán)后Eden使用率達(dá)到CMSScheduleRemarkEdenPenetration(默認(rèn)50%)后會(huì)退出;
這個(gè)階段循環(huán)執(zhí)行的目的是盡量減小下一個(gè)重新標(biāo)記階段需要處理的新生代對象引用老年代對象的情況,因?yàn)橄乱粋€(gè)階段會(huì)觸發(fā)STW,為提高吞吐量自然是dirty狀態(tài)的內(nèi)存越少越好。如果剛好在這個(gè)循環(huán)執(zhí)行的5秒內(nèi)觸發(fā)了YGC,然后這個(gè)階段又并發(fā)了處理了dirty的引用,則下個(gè)節(jié)點(diǎn)需要重新標(biāo)記的對象就沒那么大,STW時(shí)間也就短了。 上一個(gè)并發(fā)預(yù)清理節(jié)點(diǎn)可以不要的原因就是這一步其實(shí)也能達(dá)到預(yù)清理的效果,而且是循環(huán)操作的。 5. 重新標(biāo)記:較慢,CMS的瓶頸點(diǎn),觸發(fā)STW,并發(fā)重新標(biāo)記。雖然Preclean和AbortablePreclean已經(jīng)盡量處理了DirtyCard,但是不能保證完全處理掉,因此還需要重新標(biāo)記,要進(jìn)行如下處理:
遍歷新生代對象,重新標(biāo)記; 這個(gè)節(jié)點(diǎn)要遍歷新生代對象,如果新生代使用率很高,對象很多的話會(huì)耗時(shí)很久去遍歷,因此如果在進(jìn)行重新標(biāo)記之前觸發(fā)了YGC,這個(gè)步驟的耗時(shí)會(huì)減少很多。CMS可以通過參數(shù)CMSScavengeBeforeRemark來強(qiáng)制在重新標(biāo)記階段之前進(jìn)行一次YGC,該配置默認(rèn)關(guān)閉。開啟的話可能會(huì)出現(xiàn)連續(xù)的兩次YGC,也挺浪費(fèi)時(shí)間。 進(jìn)行一次YGC之后并不是要把DirtyCard交給重新標(biāo)記階段的5.3執(zhí)行,而是交給4可中斷預(yù)處理來執(zhí)行。
遍歷GCRoots,重新標(biāo)記;
遍歷DirtyCard,重新標(biāo)記,這時(shí)候經(jīng)過前兩個(gè)階段的處理,DirtyCard已經(jīng)減少了很多。
并發(fā)清除:根據(jù)標(biāo)記結(jié)果清除垃圾對象,不觸發(fā)STW,速度較慢。
并發(fā)重置:重置CMS內(nèi)部的數(shù)據(jù),如CardTable、Mod-Uniod Table等,為下一次GC做準(zhǔn)備,不觸發(fā)STW。
CMS的兩個(gè)標(biāo)記階段,都會(huì)觸發(fā)STW,不一樣之處在于,初始標(biāo)記僅標(biāo)記GCRoots和新生代可達(dá)的老年代對象,沒有再遞歸遍歷標(biāo)記,較快完成;而重新標(biāo)記階段,標(biāo)記GCRoots、新生代可達(dá)、DirtyCard中的老年代對象,且遞歸遍歷標(biāo)記,比較耗時(shí)。
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。
文章標(biāo)題:JVM內(nèi)存分區(qū)及GC知識點(diǎn)是什么
URL分享:http://chinadenli.net/article40/giigho.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、品牌網(wǎng)站制作、靜態(tài)網(wǎng)站、建站公司、小程序開發(fā)、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)