日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

JVM菜鸟进阶高手之路

發(fā)布時(shí)間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM菜鸟进阶高手之路 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文轉(zhuǎn)載自公眾號(hào) ?匠心零度

問(wèn)題現(xiàn)象

代碼如下,使用 ParNew + Serial Old 回收器組合與使用 ParNew + CMS 回收器組合時(shí),結(jié)果為什么差異如此之大 ?

private static final int _1MB = 1024 * 1024;public static void main(String[] args) throws Exception {byte[] all1 = new byte[2 * _1MB];byte[] all2 = new byte[2 * _1MB];byte[] all3 = new byte[2 * _1MB];byte[] all4 = new byte[7 * _1MB];System.in.read();}

jvm參數(shù)配置如下:

  • -Xmx20m

  • -Xms20m

  • -Xmn10m

  • -XX:+UseParNewGC

  • -XX:+UseConcMarkSweepGC

  • -XX:+UseCMSInitiatingOccupancyOnly

  • -XX:CMSInitiatingOccupancyFraction=75

  • 通過(guò)jstat命令,查看結(jié)果如下:

    關(guān)于jstat命令詳情可以參考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

    jvm參數(shù)調(diào)整如下:

  • -Xmx20m

  • -Xms20m

  • -Xmn10m

  • -XX:+UseParNewGC

  • 通過(guò)jstat命令,查看結(jié)果如下:

    說(shuō)明

    上面的題目?jī)H僅是一個(gè)切入點(diǎn)而已,希望通過(guò)一個(gè)切入點(diǎn)把jvm的一些基礎(chǔ)知識(shí)剛剛好說(shuō)明下,順便解答下上面的現(xiàn)象。

    內(nèi)存相關(guān)簡(jiǎn)單說(shuō)明

    圖中參數(shù):-Xms設(shè)置最小堆空間大小(一般建議和-Xmx一樣)。-Xmx設(shè)置最大堆空間大小。-Xmn設(shè)置新生代大小。-XX:MetaspaceSize設(shè)置最小元數(shù)據(jù)空間大小。-XX:MaxMetaspaceSize設(shè)置最大元數(shù)據(jù)空間大小。-Xss設(shè)置每個(gè)線程的堆棧大小(這里有個(gè)故事,3年前用正則表達(dá)式,后續(xù)有空正則表達(dá)式再說(shuō))。

    備注:tenured空間就用減法操作即可明白,堆空間大小減去年輕代大小就可以了。

    說(shuō)到這里,下面這個(gè)幾個(gè)參數(shù)應(yīng)該明白了。

  • -Xmx20m

  • -Xms20m

  • -Xmn10m

  • 備注:參數(shù)-XX:SurvivorRatio用來(lái)表示s0、s1、eden之間的比例,默認(rèn)情況下-XX:SurvivorRatio=8表示 s0:s1:eden=1:1:8。

    得出結(jié)論:eden=8M,s0=1M,s1=1M,tenured=10M。

    JVM垃圾回收期組合

    還有一個(gè)問(wèn)題需要解決,jvm垃圾回收器方面,下面這個(gè)圖,我是我的JVM菜鳥(niǎo)進(jìn)階高手之路八(一些細(xì)節(jié)),里面的,當(dāng)時(shí)依稀記得這個(gè)圖應(yīng)該是飛哥發(fā)給我的。

    由于那個(gè)時(shí)候jdk9還沒(méi)有出來(lái),可以去看看我的JVM菜鳥(niǎo)進(jìn)階高手之路十二(jdk9、JVM方面變化, 蹭熱度),雖然有些有些稍微去掉了,但是整體的組合還是影響不大。

    由于上面的2個(gè)jvm參數(shù)都是基于分代收集算法的(先不考慮G1

    • 依據(jù)對(duì)象的存活周期進(jìn)行分為新生代,老年代。

    • 根據(jù)不同代的特點(diǎn),選取合適的收集算法

    • 新生代,適合復(fù)制算法

    • 老年代,適合標(biāo)記清理或者標(biāo)記壓縮

    復(fù)制算法

    • 將原有的內(nèi)存空間分為兩塊,每次只使用其中一塊,在垃圾回收時(shí),將正在使用的內(nèi)存中的存活對(duì)象復(fù)制到未使用的內(nèi)存塊中,之后,清除正在使用的內(nèi)存塊中的所有對(duì)象,交換兩個(gè)內(nèi)存的角色,完成垃圾回收。

    • 不適用于存活對(duì)象較多的場(chǎng)合 如老年代。(年輕代對(duì)象基本都是朝生夕滅所以特別適合,由于那樣的話復(fù)制就少,如果類似老年代有大量存活對(duì)象,那么進(jìn)行復(fù)制算法性能就不是特別好了)

    備注:使用復(fù)制算法的優(yōu)點(diǎn):每次都是對(duì)其中的一塊進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況了,使用復(fù)制算法的缺點(diǎn):對(duì)空間有一定浪費(fèi),所以復(fù)制空間一般不會(huì)特別大。

    標(biāo)記清除標(biāo)記-清除算法將垃圾回收分為兩個(gè)階段:標(biāo)記階段和清除階段。在標(biāo)記階段,首先先找出根對(duì)象,標(biāo)記所有從根節(jié)點(diǎn)開(kāi)始的可達(dá)對(duì)象。因此,未被標(biāo)記的對(duì)象就是未被引用的垃圾對(duì)象。然后,在清除階段,清除所有未被標(biāo)記的對(duì)象。

    備注:java根對(duì)象:

    • 虛擬機(jī)棧中引用的對(duì)象。

    • 方法區(qū)中類靜態(tài)屬性實(shí)體引用的對(duì)象。

    • 方法區(qū)中常量引用的對(duì)象。

    • 本地方法棧中JNI引用的對(duì)象。

    • 等等。

      標(biāo)記清除算法缺點(diǎn):標(biāo)記清除會(huì)產(chǎn)生不連續(xù)的內(nèi)存碎片,如果空間內(nèi)存碎片過(guò)多會(huì)導(dǎo)致,當(dāng)程序在運(yùn)行過(guò)程中需要分配空間時(shí)找不到足夠的連續(xù)空間而不得不提前觸發(fā)一次垃圾收集動(dòng)作(根據(jù)算法不一樣效果也不一樣)。

    標(biāo)記壓縮標(biāo)記-壓縮算法適合用于存活對(duì)象較多的場(chǎng)合,如老年代。它在標(biāo)記-清除算法的基礎(chǔ)上做了一些優(yōu)化。和標(biāo)記-清除算法一樣,標(biāo)記-壓縮算法也首先需要從根節(jié)點(diǎn)開(kāi)始,對(duì)所有可達(dá)對(duì)象做一次標(biāo)記。但之后,它并不簡(jiǎn)單的清理未標(biāo)記的對(duì)象,而是將所有的存活對(duì)象壓縮到內(nèi)存的一端。之后,清理邊界外所有的空間。

    備注:這樣帶來(lái)的好處就是不會(huì)參數(shù)內(nèi)存碎片問(wèn)題了。

    上面已經(jīng)說(shuō)明了這么多了,我們可以繼續(xù)說(shuō)明上題中JVM的其他參數(shù)了。

  • -XX:+UseParNewGC

  • -XX:+UseConcMarkSweepGC

  • -XX:+UseParNewGC 表示新生代使用ParNew并行收集器,-XX:+UseConcMarkSweepGC 表示老年代使用CMS回收器(CMS收集器是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的,特別提醒由于CMS是標(biāo)記清除算法實(shí)現(xiàn)的所以是存在碎片問(wèn)題的)。可以去看看我的JVM菜鳥(niǎo)進(jìn)階高手之路六(JVM每隔一小時(shí)執(zhí)行一次Full GC)、以及JVM菜鳥(niǎo)進(jìn)階高手之路七(tomcat調(diào)優(yōu)以及tomcat7、8性能對(duì)比)圖片就取的這兩篇里面的。

    備注:通過(guò)jstat -gcutil pid 查看的FGC這列的時(shí)候,CMS gc通常都是+2一次的,由于CMS-initial-mark和CMS-remark會(huì)stop-the-world。

    所以看到這個(gè)圖的FGC應(yīng)該沒(méi)有什么問(wèn)題了吧。

  • -XX:+UseCMSInitiatingOccupancyOnly

  • -XX:CMSInitiatingOccupancyFraction=75

  • 還有這2個(gè)參數(shù)關(guān)于cms的,-XX:+UseCMSInitiatingOccupancyOnly表示JVM不基于運(yùn)行時(shí)收集的數(shù)據(jù)來(lái)啟動(dòng)CMS垃圾收集周期通過(guò)CMSInitiatingOccupancyFraction的值進(jìn)行每一次CMS收集,-XX:CMSInitiatingOccupancyFraction=75 表示當(dāng)老年代的使用率達(dá)到閾值75%時(shí)會(huì)觸發(fā)CMS GC。

    備注:jstat -gcutil可以看出上圖的老年代的使用率才60.02%

    還有最后一個(gè)參數(shù)解釋:

  • -XX:+UseParNewGC

  • -XX:+UseParNewGC 表示新生代使用ParNew并行收集器,那么老年代呢?可以讓同樣參數(shù)修改代碼執(zhí)行一次old gc即可看日志有類似[Tenured:說(shuō)明老年代使用的是Serial Old

    備注:Serial Old使用的是標(biāo)記壓縮算法。

    解題

  • private?static?final?int?_1MB =?1024?*?1024;

  • ? ?public?static?void?main(String[] args)?throws?Exception?{

  • ? ? ? ?byte[] all1 =?new?byte[2?* _1MB];

  • ? ? ? ?byte[] all2 =?new?byte[2?* _1MB];

  • ? ? ? ?byte[] all3 =?new?byte[2?* _1MB];

  • ? ? ? ?byte[] all4 =?new?byte[7?* _1MB];

  • ? ? ? ?System.in.read();

  • ? ?}

  • 說(shuō)明:最后System.in.read();這句可以忽略,只是為了讓程序阻塞在那里,不結(jié)束,這樣好看日志,好看現(xiàn)象而已。

    聰明如你一下子應(yīng)該可以看到問(wèn)題本質(zhì):同一份代碼,jvm參數(shù)堆設(shè)置啥的都一樣,年輕代gc參數(shù)也一樣,唯一不同的就在于老年代gc使用上面,而jstat -gcutil圖表中FGC沒(méi)變的應(yīng)該是正常結(jié)果,變了的CMS那個(gè)就是意外結(jié)果,所以關(guān)鍵點(diǎn)就在CMS上面了。

    先來(lái)說(shuō)說(shuō)all1 、all12、all3、對(duì)象實(shí)例化開(kāi)辟空間之后,eden空間都?jí)?#xff0c;他們都在eden空間中,當(dāng)all4過(guò)來(lái)的時(shí)候,eden空間不夠了,需要執(zhí)行ygc了。下面有2個(gè)問(wèn)題需要說(shuō)明,1、如果s0能存的下,可以看看JVM菜鳥(niǎo)進(jìn)階高手之路三:MaxTenuringThreshold新生代的對(duì)象正常情況下最多經(jīng)過(guò)多少次YGC的過(guò)程會(huì)晉升到老生代(CMS情況下默認(rèn)為6),說(shuō)到這里可能還需要提一個(gè)參數(shù):-XX:TargetSurvivorRatio,可以參考飛哥的:JVM Survivor行為一探究竟(http://www.jianshu.com/p/f91fde4628a5) 2、如果s0存不下,就是我們這里的情況(由于我們這里s0就是1M而已)所以直接進(jìn)入到old空間了,所以可以看出來(lái)jstat -gcutil 里面的老年代的比例都是60%幾了吧。ygc執(zhí)行完成之后,all4就還可以在eden分配(空間夠),所以可以看出來(lái)jstat -gcutil 里面的eden的比例都是89%幾了吧

    備注:-XX:PretenureSizeThreshold參數(shù)來(lái)設(shè)置多大的對(duì)象直接進(jìn)入老年代(這個(gè)參數(shù)其實(shí)只對(duì)串行回收器和ParNew有效,對(duì)ParallelGC無(wú)效)。

    如果是-Xmx20m -Xms20m -Xmn10m -XX:+UseParNewGC 這套參數(shù),那么結(jié)果就是如圖可以解釋了,并且每個(gè)參數(shù)比例啥的都可以理解了。

    下面來(lái)好好解釋下這個(gè)現(xiàn)象:聰明如你一下子應(yīng)該可以看到一個(gè)問(wèn)題,那么就是時(shí)間間隔是每隔2s執(zhí)行一次,沒(méi)錯(cuò)就是2s執(zhí)行一次。需要說(shuō)道-XX:CMSWaitDuration(Time in milliseconds that CMS thread waits for young GC)默認(rèn)值是2s,我們修改為-XX:CMSWaitDuration=5000看看效果:看到了吧,修改為5s就是5s執(zhí)行一次變化了。那么至于為什么會(huì)執(zhí)行呢??

    本題就是當(dāng)前新生代的對(duì)象是否能夠全部順利的晉升到老年代,如果不能,會(huì)觸發(fā)CMS GC。



    —————END—————



    總結(jié)

    以上是生活随笔為你收集整理的JVM菜鸟进阶高手之路的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。