運(yùn)行時數(shù)據(jù)區(qū)(Run-Time Data Areas)
- 本地方法區(qū):方法區(qū)和堆一樣,也是被所有線程共享的內(nèi)存區(qū)域丽旅。它存儲已被虛擬機(jī)加載的類信息椰棘,常量,靜態(tài)變量榄笙,即時編譯后的代碼數(shù)據(jù)邪狞。
- 虛擬機(jī)棧(JVM Stacks):每個Java虛擬機(jī)線程都有一個私有Java虛擬機(jī)棧,與線程同時創(chuàng)建茅撞。每個方法執(zhí)行的同時都會創(chuàng)建一個棧帆卓,用于存儲局部變量表,操作數(shù)棧米丘,動態(tài)鏈接剑令,方法出口等信息,每一個方法從調(diào)用到直至完成的過程拄查,對應(yīng)著一個棧在虛擬機(jī)中入棧到出棧的過程吁津。
- 本地方法棧:與虛擬機(jī)棧發(fā)揮的作用類似,他們之間的區(qū)別是:虛擬機(jī)棧是為虛擬機(jī)執(zhí)行Java方法提供服務(wù)堕扶;本地方法棧是為虛擬機(jī)執(zhí)行native方法服務(wù)碍脏。
- 堆(Heap ):堆是所有線程之間共享的內(nèi)存區(qū)域。堆是運(yùn)行時數(shù)據(jù)區(qū)稍算,從中分配所有類實(shí)例和數(shù)組的內(nèi)存潮酒。堆是在虛擬機(jī)啟動時創(chuàng)建的。
- 程序計數(shù)器(PC Register):JVM支持多線程同時執(zhí)行邪蛔,每個線程都有自己的PC Register,線程正在執(zhí)行的方法叫當(dāng)前方法扎狱。如果該方法不是 native方法侧到,則PC Register包含當(dāng)前正在執(zhí)行的Java虛擬機(jī)指令的地址。如果線程當(dāng)前正在執(zhí)行該方法是native方法淤击,則Java虛擬機(jī)PC Register的值未定義匠抗。
- 運(yùn)行時常量池:是方法區(qū)的一部分。Class文件除了版本污抬,字段汞贸,方法绳军,接口等描述信息外,還有一項(xiàng)信息是常量池矢腻,用于存放編譯期生成的字面量和符號的引用门驾,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時常量池存放。
Java的內(nèi)存結(jié)構(gòu)
常用JVM配置參數(shù)
- -Xms jvm初始的堆內(nèi)存大小多柑,默認(rèn)為物理內(nèi)存的1/64奶是,等價于 -XX:InitialHeapSize=
- -Xmx jvm最大的堆內(nèi)存大小,默認(rèn)為物理內(nèi)存的1/4,等價于 -XX:MaxHeapSize=
- -Xss 設(shè)置單個線程棧的大小竣灌,默認(rèn)512k-1024k聂沙,等價于 -XX:ThreadStackSize
- -Xmn 設(shè)置新生代的大小,默認(rèn)為堆空間的1/3
- -XX:MetaSpaceSize:設(shè)置元空間的大小初嘹,元空間本質(zhì)和永久代類似及汉,都是對JVM規(guī)范中本地方法區(qū)的實(shí)現(xiàn)。不過元空間與永久代最大的區(qū)別在于:元空間并不在虛擬機(jī)中屯烦,而是使用本地內(nèi)存坷随,因此默認(rèn)情況下,元空間的大小僅受物理內(nèi)存大小的限制漫贞。
- -XX:+PrintGCDetails 輸出詳細(xì)GC收集日志信息
- -XX:SurvivorRatio:設(shè)置新生代中eden(survivorFrom)和S0/S1(survivorTo)的比例
默認(rèn)-XX:SurvivorRatio=8,Eden:S0:S1=8:0:0
SurvivorRatio的值就是默認(rèn)eden的比例占比甸箱,S0和S1占比相同 - -XX:NewRatio:配置新生代和老年代在堆中空間大小的比例
默認(rèn)-XX:NewRatio=2,新生代占1,老年代占2迅脐,新生代占整個堆內(nèi)存的1/3
假如-XX:NewRatio=4,新生代占1芍殖,老年代占4,新生代占整個堆內(nèi)存的1/5
NewRatio就是設(shè)置老年代的占比值谴蔑,剩下的1給新生代 - -XX:MaxTunuringThreshold 設(shè)置垃圾的最大年齡豌骏,java8默認(rèn)為15,如果設(shè)置值的話必須在0-15如果設(shè)置為0隐锭,則年輕代不經(jīng)過Survivor區(qū)窃躲,直接進(jìn)入年老代,對于老年代比較多的應(yīng)用钦睡,可以提高效率如果設(shè)置的的比較大蒂窒,則年輕代會在Survivor區(qū)進(jìn)行多次復(fù)制,這樣增加 對象在年輕代的存活時間荞怒,增加在年輕代即被回收的概率洒琢。
垃圾回收算法
1. 什么是垃圾?
簡單來說就是內(nèi)存中不可能再被使用到的對象空間就是垃圾褐桌。
2 如何確定一個對象是垃圾衰抑?可以回收
- 引用計數(shù)法:如果一個對象的引用為0,則可以回收荧嵌。但是如果兩個對象相互引用呛踊,則這兩個對象永遠(yuǎn)不可回收砾淌,所以現(xiàn)在基本不使用該方法判斷。
- 枚舉根節(jié)點(diǎn)谭网,可達(dá)性分析汪厨,Java虛擬機(jī)采用的算法◎叩祝基本思路就是通過一系列名為“GC Roots”的對象作為起始點(diǎn)骄崩,開始向下搜索,如果一個對象到GC Roots沒有任何引用鏈相連時薄辅,則說明此對象不可用要拂。也即,給一個集合的引用為根出發(fā)站楚,通過引用關(guān)系遍歷圖脱惰,能被遍歷到的就判定為存活,沒有被遍歷到的自然判定為死亡窿春。
Java中可以作為GC Roots對象有:
- 虛擬機(jī)棧(棧幀中的局部變量區(qū)拉一,也叫局部變量表)中引用的對象
- 方法區(qū)中類靜態(tài)屬性引用的對象。
- 方法區(qū)中常量引用的對象旧乞。
- 本地方法棧中Native方法引用的對象蔚润。
- 線程
3. 常用的垃圾回收算法
復(fù)制算法
java堆從GC角度還可以細(xì)分為:新生代(Eden區(qū),F(xiàn)rom Survivor區(qū)和To Survivor區(qū)尺栖,占用1/3的堆空間)和老年代(占據(jù)2/3的堆空間)嫡纠。
Minitor GC的過程(復(fù)制-清空-互換)
Eden、SurvivorFrom復(fù)制到SurvivorTo延赌,年齡+1除盏;
- 首先,當(dāng)Eden區(qū)滿的時候挫以,第一次觸發(fā)GC者蠕,把還活著的對象拷貝到SuvivorFrom區(qū),當(dāng)Eden區(qū)滿再次觸發(fā)GC的時候會掃描Eden區(qū)和SurvivorFrom區(qū)掐松,對這兩個區(qū)域進(jìn)行垃圾回收踱侣,經(jīng)過這次回收還活著的對象,則直接復(fù)制到SuvivorTo區(qū)域(如果對象的年齡達(dá)到了老年代大磺,則賦值到老年代)泻仙,同時把這些對象的年齡+1;
- 清空Eden和SurvivorFrom中的對象量没,也即復(fù)制之后交換,誰空誰是To;
- SurvivorFrom和SurvivorTo互換
- 最后突想,SurvivorFrom和SurvivorTo互換殴蹄,原SurvivorTo成為下一次GC時的SurvivorFrom區(qū)究抓,部分對象會在From區(qū)域和To區(qū)域復(fù)制來復(fù)制去,如此交換15次(由JVM參數(shù)MaxTenuringThreshold決定袭灯,這個參數(shù)默認(rèn)是15)
- 最終如果還是存活刺下,就存入老年代。
優(yōu)點(diǎn):整體復(fù)制稽荧,沒有產(chǎn)生內(nèi)存碎片橘茉。
缺點(diǎn):浪費(fèi)空間,大對象復(fù)制會耗時姨丈。
標(biāo)記清除
先標(biāo)記出要回收的對象畅卓,再統(tǒng)一回收這些要清除的對象。
優(yōu)點(diǎn):沒有大面積的復(fù)制蟋恬,節(jié)約內(nèi)存空間
缺點(diǎn):產(chǎn)生內(nèi)存碎片翁潘。
標(biāo)記整理
標(biāo)記要回收的對象,再次掃描歼争,并往一端滑動存活的對象拜马。
優(yōu)點(diǎn):沒有內(nèi)存碎片,可以使用bump.
缺點(diǎn):移動存活對象的成本沐绒,耗時間俩莽。
主流的三種算法各有優(yōu)缺點(diǎn),綜合來看乔遮,使用分代收集扮超,復(fù)制算法用于年輕代,標(biāo)記清除申眼,標(biāo)記整理用于老年代瞒津。
GC垃圾回收算法和垃圾收集器的關(guān)系?
GC算法(引用計數(shù)括尸,復(fù)制巷蚪,標(biāo)記整理,標(biāo)記清除)是內(nèi)存垃圾回收的方法論濒翻。垃圾收集器就是GC算法的落地實(shí)現(xiàn)屁柏。
因?yàn)槟壳盀橹惯€沒有出現(xiàn)完美的垃圾回收器出現(xiàn),更加沒有萬能的收集器有送,只有針對具體的應(yīng)用最合適和垃圾回收器淌喻,進(jìn)行分代收集。
4種主要的垃圾收集器
- serial 串行垃圾回收器:他為單線程環(huán)境設(shè)計且只使用一個線程進(jìn)行垃圾回收雀摘,會暫停所有的用戶線程所以不適合服務(wù)器環(huán)境裸删。
- paraller 并行垃圾回收器:多個垃圾收集線程并行工作,此時用戶的線程是暫停的阵赠,適用于科學(xué)計算涯塔,大數(shù)據(jù)處理首臺處理等弱交互的場景肌稻。
- CMS 并發(fā)垃圾回收器:用戶線程和垃圾回收線程同時執(zhí)行(不一定是并行,有可能交替進(jìn)行)匕荸,不需要停頓用戶線程互聯(lián)網(wǎng)公司多使用他爹谭,對于響應(yīng)有時間限制的場景。
- G1垃圾回收器:將堆內(nèi)存分割為不同的區(qū)域榛搔,然后并發(fā)的對其進(jìn)行垃圾回收诺凡。
如何選用合適的垃圾收集器?
組合的選擇:
1践惑、單核的CPU或者小內(nèi)存腹泌,單機(jī)程序
-XX:UseSerialGC
2、多CPU童本,需要最大吞吐量真屯,如后臺計算型應(yīng)用
-XX:UseParallelGC 或者-XX:UseParallelOldGC
3、多CPU,追求最小停頓時間穷娱,最快速響應(yīng)绑蔫,如互聯(lián)網(wǎng)應(yīng)用
-XX:+UserConcMarkSweepGC
-XX:+ParNewGC
參考鏈接:JVM官方規(guī)范