目錄
一、內(nèi)存區(qū)域
二径玖、內(nèi)存溢出和內(nèi)存泄漏
三痴脾、實(shí)操OutOfMemoryError
四、對(duì)象的創(chuàng)建和對(duì)象的內(nèi)存布局
五梳星、JVM調(diào)參集錦
一赞赖、內(nèi)存區(qū)域
線程共享內(nèi)存區(qū):方法區(qū)、堆
線程獨(dú)有內(nèi)存區(qū):虛擬機(jī)棧冤灾、本地方法棧前域、程序計(jì)數(shù)器
注意:線程共享內(nèi)存區(qū)就是我們常要考慮內(nèi)存回收的地方、而線程獨(dú)有內(nèi)存區(qū)是會(huì)隨著線程的執(zhí)行結(jié)束而消亡的韵吨,不需要考慮內(nèi)存回收
1.程序計(jì)數(shù)器(program counter register)
定義:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器
獨(dú)占線程:程序計(jì)數(shù)器屬于線程獨(dú)占去,每個(gè)線程都有一個(gè)程序計(jì)數(shù)器
-
字節(jié)碼計(jì)數(shù)器如何工作?
通過改變程序計(jì)數(shù)器的值來讀取下一條字節(jié)碼指令
(分支话侄、循環(huán)、異常處理学赛、線程恢復(fù)都依賴計(jì)數(shù)器) java方法:計(jì)數(shù)器記錄的是正在執(zhí)行的字節(jié)碼指令的地址
native方法:值為空(undefined)
此內(nèi)存無OOM:此區(qū)域是唯一一個(gè)在jvm規(guī)范中沒有固定任何OutOfMemory情況的區(qū)域
保留字:java中的goto,現(xiàn)在不用,可能以后會(huì)用,暫不開發(fā),防止以后jdk出現(xiàn)新功能的時(shí)候之前的程序全部報(bào)錯(cuò)
2.虛擬機(jī)棧
- 定義:
描述的是java方法執(zhí)行的動(dòng)態(tài)內(nèi)存模型,
線程私有(創(chuàng)建一個(gè)方法就有創(chuàng)建一個(gè)棧幀push,方法調(diào)用執(zhí)行完成,對(duì)應(yīng)的棧幀pop)
每一個(gè)方法從調(diào)用開始到執(zhí)行完成的過程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧里面從入棧到出棧的過程吞杭。 - 棧幀定義:存放著局部變量表,操作棧,動(dòng)態(tài)鏈接,方法出口
-
局部變量表
- 定義:基本數(shù)據(jù)類:(boolean,byte,char,short,int,long,float,double)
- 對(duì)象引用:(reference),可能是引用指針,對(duì)象句柄,對(duì)象相關(guān)的位置,字節(jié)碼指令地址
- 局部變量表內(nèi)存固定:局部變量表內(nèi)存在編譯的期間完成分配,運(yùn)行期間不會(huì)改變局部變量表的大小
- 總結(jié):Java的八大基礎(chǔ)數(shù)據(jù)(32位可放下),64位高低兩個(gè)存放,局部的對(duì)象則存放用對(duì)象的引用
-
操作數(shù)棧
- 定義:是棧幀中一個(gè)先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),虛擬機(jī)將這里作為他的工作區(qū),方法區(qū)中進(jìn)行add算數(shù)運(yùn)算或者參數(shù)傳遞是通過操作數(shù)棧
- 操作數(shù)棧理論獨(dú)立,但大部分虛擬機(jī)會(huì)優(yōu)化,一部分?jǐn)?shù)據(jù)可以實(shí)現(xiàn)棧幀共享,這樣方法調(diào)用,無需額外的參數(shù)復(fù)制傳遞
- 總結(jié):操作的元素是任意的java數(shù)據(jù)類型,一個(gè)方法剛剛開始的時(shí)候,操作數(shù)棧是空的,操作數(shù)棧運(yùn)行方法是JVM一直在入棧/出棧的過程
-
動(dòng)態(tài)鏈接
每個(gè)棧幀都包含一個(gè)(指向常量池中該棧幀所屬方法)的引用,用來支持動(dòng)態(tài)鏈接的實(shí)現(xiàn),符號(hào)引用(名字)和直接引用(地址)在運(yùn)行時(shí)進(jìn)行解釋和鏈接的過程,稱為動(dòng)態(tài)鏈接- 部分符號(hào)引用在類加載階段(解析)的時(shí)候就轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化為靜態(tài)鏈接
- 部分符號(hào)引用在運(yùn)行期間轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化為動(dòng)態(tài)鏈接
方法出口:(返回地址)
正常返回:調(diào)用PC程序計(jì)數(shù)器的地址進(jìn)行返回,即調(diào)用該方法的下一條指令地址
異常返回:異常處理器表<非棧幀中的>來確定,棧幀一般不會(huì)保存這部分信息-
圖解
image-20200716065525058.png
-
StackOverflowError:當(dāng)棧深度大于虛擬機(jī)所允許的最大長(zhǎng)度
Exception in thread "main" java.lang.StackOverflowError
OOM:虛擬機(jī)椪到剑可動(dòng)態(tài)擴(kuò)展的情況,無法申請(qǐng)到足夠的物理內(nèi)存,會(huì)報(bào)OOM錯(cuò)誤
3.本地方法棧
(HotSpot不分虛擬機(jī)棧和本地方法棧)
因此對(duì)于HotSpot來說,-Xoss參數(shù)(設(shè)置本地方法棧大小)雖然存在芽狗,但實(shí)際上是無效的绢掰,棧容量只由-Xss .
- 本地方法棧:為虛擬機(jī)使用到的native方法服務(wù)
- 虛擬機(jī)棧:為虛擬機(jī)執(zhí)行Java方法(字節(jié)碼)服務(wù)
- 但本地方法棧并不是用 Java 實(shí)現(xiàn)的,而是由 C 語言實(shí)現(xiàn)的。
- 何為native方法:
"A native method is a Java method whose implementation is provided by non-java code."
1.Native方法就是java調(diào)用非java代碼的接口,這個(gè)接口的實(shí)現(xiàn)不是java寫的
2.C++中,你可以extern "C"告知c++編譯器調(diào)用c函數(shù)
4.堆內(nèi)存
定義:存放所有對(duì)象實(shí)例,GC垃圾回收器管理最大的區(qū)域,可以處于物理上不連續(xù)的內(nèi)存空間
"不一定"存所有對(duì)象實(shí)例:JIT編譯器優(yōu)化----出現(xiàn)虛擬機(jī)棧上分配
-
新生代(Young Generation):很快就會(huì)被GC回收掉的或者不是特別大的對(duì)象滴劲。
1.劃分為Eden(伊甸園)和Survivor區(qū)攻晒,最后Survivor由FromSpace和ToSpace組成,三個(gè)區(qū)域默認(rèn)情況下是按照8:1:1分配,也可以手動(dòng)配置。
2.JVM每次只會(huì)使用Eden區(qū)和一塊Survivor區(qū)來為對(duì)象服務(wù),另一塊Survivor區(qū)域是空的,用于垃圾回收
3.舉例:
第一次GC,將Eden+from存活的對(duì)象復(fù)制到to,清空Eden和from(存活對(duì)象小于to的空間)
第二次GC,虛擬機(jī)使用Eden+to,將存活對(duì)象移到from
就這樣反復(fù)在from,to循環(huán),復(fù)制過程內(nèi)存不夠使用則向老年代分配擔(dān)保 老年代(Old Generation):
Tenured Gen
新生代每一次GC后,都給對(duì)象"+1歲",當(dāng)年齡到達(dá)一定數(shù)量則會(huì)進(jìn)入老年代
(默認(rèn)15, -XX:MaxTenuringThreshold設(shè)置)
大的對(duì)象直接進(jìn)入老年代
(默認(rèn)15, -XX:PretenuringThreshold設(shè)置)
-XX:PretenureSizeThreshold3M班挖,那么大于3M的對(duì)象就會(huì)直接就進(jìn)入老年代鲁捏。永久代/持久代(Permanent Generation ):即JVM的方法區(qū)
存放一些虛擬機(jī)加載的類信息的靜態(tài)文件,更不易被回收TLAB(thread local allocation buffer):分配緩沖區(qū)
堆內(nèi)存是線程共享的,堆上分配的內(nèi)存需要加鎖,為了提高效率,會(huì)為每個(gè)新建的線程在Eden上分配一塊獨(dú)立空間線程獨(dú)享,在TLAB上不需要加鎖,所有JVM給線程中的對(duì)象分配內(nèi)存會(huì)優(yōu)先使用AB分配緩沖區(qū)
如何創(chuàng)建對(duì)象
對(duì)象分配內(nèi)存 -> 內(nèi)存初始化 -> 對(duì)象初始化 -> 構(gòu)造方法
- 指針碰撞(雙指針) free區(qū) |正在分配內(nèi)存|已用區(qū)域
- 空閑列表
線程安全:TLAB
5.方法區(qū)
- 定義:用于存儲(chǔ)被虛擬機(jī)加載的(類信息包括常量池),靜態(tài)變量,常量,編譯后的代碼
- 方法區(qū)是堆的邏輯部分,但是與堆內(nèi)存分開的。
- 類信息:類的版本,類的全限定名,字段,方法,接口
- 執(zhí)行類.class的過程
- 在加載類(加載萧芙、(驗(yàn)證给梅、準(zhǔn)備、解析3步稱為連接)双揪、初始化)
- 永久代:HotSpot虛擬機(jī)特有的概念,HotSpot 虛擬機(jī)使用永久代來實(shí)現(xiàn)方法區(qū)动羽,
- 版本的改動(dòng):
- JDK1.7的HotSpot:方法區(qū)移除了字符串常量池
- JDK1.8的HotSpot:取消了方法區(qū),用元空間(Meta Space)代替
- 元空間的大小參數(shù)
JDK1.7及以前(初始和最大值):-XX:PermSize -XX:MaxPermSize
JDK1.8(初始和最大值):-XX:MetaSpaceSize -XX:MaxMetaSpaceSize
6.元空間
- 定義:元空間的本質(zhì)和永久代類似,都是對(duì)JVM中方法區(qū)的實(shí)現(xiàn),最大的區(qū)別是元空間使用的是本地內(nèi)存
- 為什么要用元空間代替永久代?
- 性能和OOM問題:字符串在永久代,容易出現(xiàn)性能問題和內(nèi)存溢出問題
- 空間大小導(dǎo)致溢出:類及方法的信息比較難確定大小,永久代的內(nèi)存大小指定困難,小-->永久代溢出(方法區(qū)太小), 大-->老年代溢出(堆內(nèi)存太小)
- GC回收效率低
7.運(yùn)行時(shí)常量池
- 定義:方法區(qū)的一部分(.class文件)中的常量池(存放編譯時(shí)的引用)會(huì)在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池
- 幼兒園化:java文件編譯成class文件,常量池的字面量和符號(hào)引用只是個(gè)名字而已,還沒指向?qū)?yīng)的內(nèi)存地址,類加載的時(shí)候會(huì)把這些字面量和符號(hào)引用放入運(yùn)行時(shí)常量池(runtime constant pool)并指向?qū)?yīng)的內(nèi)存地址
- 動(dòng)態(tài)性:String.intern()方法調(diào)用時(shí)可以將常量放入到運(yùn)行時(shí)常量池中
- OOM:常量池?zé)o法從方法區(qū)獲得內(nèi)存,也會(huì)拋異常OutOfMemoryError
- JDK6中,不推薦大量使用intern方法渔期,因?yàn)檫@個(gè)版本字符串緩存在永久代中运吓,這個(gè)空間是有限了,除了FullGC之外不會(huì)被清除疯趟,大量的緩存在這容易OutOfMemoryError拘哨。之后的版本把字符串放入了堆中,避免了永久代被擠滿迅办。
- JDK1.7:字符串常量池從方法區(qū)移至堆內(nèi)存中
- JDK1.8:方法區(qū)的移除,運(yùn)行時(shí)常量池移至元空間中(Meta Space)
-
避免在一個(gè)系統(tǒng)中產(chǎn)生大量的String對(duì)象宅静,引入了字符串常量池。
image-20200713094221170.png
8.直接內(nèi)存
- 定義:直接內(nèi)存并不是虛擬機(jī)運(yùn)行時(shí)的一部分,這部分卻頻繁的使用,在JDK1.4中加入NIO(New Input/Output)類,使用Native函數(shù)可以直接分配堆外地址,存儲(chǔ)在Java堆里面的DirectByteBuffer對(duì)象作為這塊堆外內(nèi)存的引用
- 好處:在一些場(chǎng)景中可以顯著提高性能,避免了在堆內(nèi)存和堆外內(nèi)存中來回拷貝數(shù)據(jù)
二站欺、內(nèi)存溢出和內(nèi)存泄漏
內(nèi)存溢出
內(nèi)存溢出:JVM在申請(qǐng)內(nèi)存的時(shí)候,因?yàn)闆]有足夠的內(nèi)存而引發(fā)的錯(cuò)誤OOM
1.堆溢出
- 原因:
- 堆內(nèi)存過小或者內(nèi)存泄漏
- 為大對(duì)象(大數(shù)組)分配內(nèi)存
- 頻繁的調(diào)用String.intern()方法,1.7(不包括)以后字符串的常量池在堆內(nèi)存中
- GC回收效率低,98%時(shí)間回收不到%2的空間
- 常用參數(shù):-Xms -Xmx(堆內(nèi)存初始容量和最大容量)
-Xms512m
2.棧溢出
-
官方:
如果線程<u>請(qǐng)求的棧深度</u>大于虛擬機(jī)所允許的最大深度姨夹,將拋出StackOverflowError異常。
如果虛擬機(jī)在<u>擴(kuò)展棧</u>時(shí)無法申請(qǐng)到足夠的內(nèi)存空間矾策,則拋出OutOfMemoryError異常磷账。 -
OutOfMemory(多線程):每個(gè)線程都有對(duì)應(yīng)的棧幀與之對(duì)應(yīng),棧內(nèi)存過大或者線程數(shù)過多都會(huì)造成OOM
-
棧內(nèi)存過大
每個(gè)線程分配到的棧容量大,可以建立的線程數(shù)就少,需要建立新線程就容易把剩下的內(nèi)存耗盡
-
線程數(shù)過多
棧內(nèi)存有限,隨著線程數(shù)的增加,棧內(nèi)存的空間就慢慢減少
-
棧內(nèi)存過大
-
StackOverflowError單線程:往往發(fā)生于單線程的錯(cuò)誤地?zé)o限遞歸,當(dāng)線程所請(qǐng)求的棧最大深度大于虛擬機(jī)所允許的最大深度(-Xss),拋出StackOverflowError
- 單線程下的棧內(nèi)存減少
- 新建本地變量,使得線程棧幀的局部變量表變大
-
常用參數(shù)
-Xss(棧容量大小,可理解為棧幀深度)
3.方法區(qū)溢出
- 定義:方法區(qū)存儲(chǔ)的是JVM加載的類信息,靜態(tài)變量,常量,JIT編譯后的代碼,經(jīng)常動(dòng)態(tài)生成大量class的應(yīng)用中,要注意會(huì)不會(huì)出現(xiàn)OOM
- 出現(xiàn)得到情況
- 大量的JSP,JSP第一次訪問時(shí),JSP引擎會(huì)將JSP轉(zhuǎn)換編譯成Class,加入內(nèi)存
- JDK1.7以前(不包括1.7)的HotSpot頻繁的使用String.intern().那時(shí)的字符串常量池還在方法區(qū)
- 存在大量反射的場(chǎng)景,也會(huì)把class加載進(jìn)內(nèi)存
- 常用參數(shù):
1.7及其之前,通過-XX:PermSize -XX:PermSizeMax:限制方法區(qū)的大小
1.8:-XX:MetaSpaceSize -XX:MaxSpaceSize:元空間初始與最大容量
4.直接內(nèi)存溢出
- 定義:在JDK1.4中加入NIO(New Input/Output)類,使用Native函數(shù)可以直接分配堆外地址,存儲(chǔ)在Java堆里面的DirectByteBuffer對(duì)象作為這塊堆外內(nèi)存的引用
- 直接內(nèi)存只能Full GC清理回收不像新生代和老年代,發(fā)現(xiàn)空間不足就通知GC回收
- Minor GC Major GC Full GC
從年輕代空間(包括 Eden 和 Survivor 區(qū)域)回收內(nèi)存被稱為 Minor GC。 Major GC 是清理永久代贾虽。Full GC 是清理整個(gè)堆空間—包括年輕代和永久代逃糟。(年輕代收集不能把對(duì)象放進(jìn)永久代時(shí),就會(huì)觸發(fā)一次完全收集Major-GC)
5.內(nèi)存泄漏
Memory Leak,程序在申請(qǐng)內(nèi)存后,無法釋放已申請(qǐng)的內(nèi)存空間(一個(gè)對(duì)象不再被需要了蓬豁,可是收集器卻無法將它回收) , 一次內(nèi)存泄漏危害很小,但是長(zhǎng)期堆積后很嚴(yán)重,無論有多少內(nèi)存,最終會(huì)被耗光,memory leak最終導(dǎo)致----> OOM
三绰咽、實(shí)操OutOfMemoryError
--------------------------------------進(jìn)階1-------------------------------------
--------------------jvm運(yùn)行時(shí)中添加arguments參數(shù)-------------------
Run as -> Run Configuration -> arguments(VM arguments) -> 添加以下內(nèi)容
-XX:+HeapDumpOnOutOfMemoryError -Xms20m -Xmx20m
再次運(yùn)行生成java_pid8374.hprof的快照文件
---------------------------------------進(jìn)階2----------------------------------------
--------------------MAT工具分析出現(xiàn)OOM的原因--------------------------
將java_pid8374.hprof導(dǎo)入MAT中 -> 首頁有圓形圖分析 -> open dominator tree for entire heap(樹結(jié)構(gòu)查看堆結(jié)構(gòu))
shallowed heap:自身對(duì)象占用空間
retained heap:自身對(duì)象及其引用占用空間
參數(shù)解釋:
-XX:+HeapDumpOnOutOfMemoryError -----拍攝OOM溢出的快照+配合MAT工具查看使用
-Xms20m ------初始的Heap的大小。
-Xmx20m --------Xmx最大Heap的大小地粪。
-Xss規(guī)定了每個(gè)線程棧的大小取募。一般情況下256K是足夠了。影響了此進(jìn)程中并發(fā)線程數(shù)大小蟆技。
--------------------------------------------------進(jìn)階3--------------------------------------------
------------------------------自帶的jconsole程序(實(shí)際是lib/tools.jar)--------------------------
cmd ->(配置java環(huán)境變量的情況下) -> jconsole(出現(xiàn)小程序頁面) -> 本地進(jìn)程(sun.tools.jconsole.JConsole)
四玩敏、對(duì)象的創(chuàng)建和對(duì)象的內(nèi)存布局
對(duì)象的創(chuàng)建
-
對(duì)象創(chuàng)建過程
- new 類
- new 的參數(shù)在常量池中(方法區(qū)或者M(jìn)eta Space)定位符號(hào)引用
- 沒有引用,則進(jìn)行類加載,鏈接,初始化
- 在堆中給對(duì)象分配內(nèi)存空間
- 內(nèi)存初始化=0(不包括對(duì)象頭)
- 調(diào)用對(duì)象的init方法
-
總結(jié)
- 對(duì)象分配內(nèi)存 -> 內(nèi)存初始化 -> 對(duì)象初始化 -> 構(gòu)造方法
- 指針碰撞(雙指針) free區(qū) |正在分配內(nèi)存|已用區(qū)域(GC器有相應(yīng)的劃分內(nèi)存區(qū)域的功能)
- 空閑列表
線程安全:TLAB
對(duì)象的內(nèi)存布局
- 對(duì)象頭Header
- 自身運(yùn)行數(shù)據(jù)(Mark Word)
- 哈希值hashcode / 偏向線程ID + epoch(偏向鎖的時(shí)間戳)
- GC分代年齡
- 是否偏向,鎖狀態(tài)標(biāo)志
- 類型指針:JVM通過這個(gè)指針確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例
- 自身運(yùn)行數(shù)據(jù)(Mark Word)
- 實(shí)例數(shù)據(jù)InstanceData
- 對(duì)象真正存儲(chǔ)的有效信息,定義各種類型的數(shù)據(jù),包括父類繼承下來的
- 對(duì)齊填充Padding
- 相當(dāng)于占位符,HotSpot VM的自動(dòng)內(nèi)存管理系統(tǒng)要求對(duì)象的起始地址必須是8字節(jié)的整數(shù)倍,so當(dāng)實(shí)例數(shù)據(jù)部分沒有對(duì)齊時(shí),會(huì)以對(duì)齊填充來補(bǔ)全(對(duì)象頭部部分正好8字節(jié)的1或者2倍)
- 對(duì)象的訪問定位
通過棧的引用去操作堆中的對(duì)象,引用訪問堆中對(duì)象有兩種方式- 句柄:Java堆中劃分一塊內(nèi)存作為句柄池,棧的(引用reference)存放的是對(duì)象的句柄信息,句柄包含了對(duì)象實(shí)例數(shù)據(jù)和類型數(shù)據(jù)兩塊地址信息,
好處:reference中存儲(chǔ)的是穩(wěn)定的句柄地址,對(duì)象在移動(dòng)時(shí)(GC非常的常見)只會(huì)改變句柄的實(shí)例數(shù)據(jù)指針,reference本身不需要修改 - 直接指針:堆對(duì)象需考慮如何放置訪問類型數(shù)據(jù)的相關(guān)信息,reference中直接存儲(chǔ)對(duì)象地址信息
好處:速度更快,節(jié)省了一次指針定位的開銷
Hotspot 使用的是直接指針的方式訪問對(duì)象斗忌。
- 句柄:Java堆中劃分一塊內(nèi)存作為句柄池,棧的(引用reference)存放的是對(duì)象的句柄信息,句柄包含了對(duì)象實(shí)例數(shù)據(jù)和類型數(shù)據(jù)兩塊地址信息,
五、JVM調(diào)參集錦
基礎(chǔ)
-
打印gc信息
-verbose:gc -XX:+PrintGCDetails
-
xms xmx xss xmn
- -Xms 為jvm啟動(dòng)時(shí)分配的內(nèi)存旺聚,比如-Xms200m织阳,表示分配200M,默認(rèn)為物理內(nèi)存的1/64
- -Xmx 為jvm運(yùn)行過程中分配的最大內(nèi)存,比如-Xms500m砰粹,表示jvm進(jìn)程最多只能夠占用500M內(nèi)存,默認(rèn)為物理內(nèi)存的1/4
- -Xss (虛擬機(jī)棧)為jvm啟動(dòng)的設(shè)置每個(gè)線程的堆棧大小唧躲,默認(rèn)JDK1.4中是256K,JDK1.5+中是1M
在相同物理內(nèi)存下伸眶,減小這個(gè)值能生成更多的線程惊窖。 - -Xmn4g:設(shè)置年輕代大小為4G.
-Xmn 堆內(nèi)新生代的大小。通過這個(gè)值也可以得到老生代的大欣逶簟:-Xmx減去-Xmn
-
非堆內(nèi)存分配:
-XX:NewRatio=4
設(shè)置年輕代(包括Eden和兩個(gè)Survivor區(qū))與年老代的比值(除去持久代)界酒。設(shè)置為4,則年輕代與年老代所占比值為1:4嘴秸,年輕代占整個(gè)堆棧的1/5毁欣。
-XX:SurvivorRatio=4
設(shè)置年輕代中Eden區(qū)與Survivor區(qū)的大小比值。設(shè)置為4岳掐,則兩個(gè)Survivor區(qū)與一個(gè)Eden區(qū)的比值為2:4凭疮,一個(gè)Survivor區(qū)占整個(gè)年輕代的1/6。(4:1:1)串述。
-XX:MaxPermSize=16m 設(shè)置持久代大小為16m执解。
-XX:MaxTenuringThreshold=0
設(shè)置垃圾最大年齡。大于這個(gè)年齡的都會(huì)進(jìn)入老年代區(qū)纲酗。如果設(shè)置為0的話衰腌,則年輕代對(duì)象不經(jīng)過Survivor區(qū),直接進(jìn)入年老代觅赊。對(duì)于年老代比較多的應(yīng)用右蕊,可以提高效率。如果將此值設(shè)置為一個(gè)較大值吮螺,則年輕代對(duì)象會(huì)在Survivor區(qū)進(jìn)行多次復(fù)制饶囚,這樣可以增加對(duì)象再年輕代的存活時(shí)間,增加在年輕代即被回收的概論鸠补。
進(jìn)階
- 修改收集器
串行收集器DefNew:是使用-XX:+UseSerialGC(新生代萝风,老年代都使用串行回收收集器)
并行收集器ParNew:是使用-XX:+UseParNewGC(新生代使用并行收集器,老年代使用串行收集器)
并行收集器PSYoungGen:是使用-XX:+UseParallelOldGC(新生代紫岩,老年代都使用并行回收收集器)或者-XX:+UseParallelGC(新生代使用并行回收收集器闹丐,老年代使用串行收集器)
并發(fā)收集器CMS: -XX:+UseConcMarkSweepGC(新生代使用并行收集器,老年代使用CMS)被因。
并發(fā)收集器garbage-first heap:是使用-XX:+UseG1GC(G1收集器) - 大對(duì)象直接進(jìn)入老年代
why?如果放在年輕代的Eden,GC頻繁,采用復(fù)制算法導(dǎo)致經(jīng)常移動(dòng)大對(duì)象,這會(huì)消耗資源
-XX:PretenureSizeThreshold=6M 超過6M直接分配到進(jìn)老年代 - 存活年齡多大的對(duì)象進(jìn)入老年代
-XX:MaxTenuringThreshold 15 設(shè)置的是年齡閾值卿拴,默認(rèn)15(對(duì)象被復(fù)制的次數(shù))
-
允許分配擔(dān)保:Eden區(qū)域從老年代借空間(相當(dāng)于貸款)
JVM繼續(xù)檢查老年代最大的可用連續(xù)空間是否大于歷次晉升到老年代的對(duì)象的平均大小,如果大于梨与,則正常進(jìn)行一次YGC堕花,盡管有風(fēng)險(xiǎn)(因?yàn)榕袛嗟氖瞧骄笮。锌赡苓@次的晉升對(duì)象比平均值大很多)粥鞋;
如果小于缘挽,或者HandlePromotionFailure設(shè)置不允許空間分配擔(dān)保,這時(shí)要進(jìn)行一次FGC呻粹。-XX:+HandlePromotionFailure 允許分配擔(dān)保