成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

jvm內(nèi)存分配策略和性能監(jiān)控

Baoyuan / 606人閱讀

摘要:概述本篇旨在講清楚的內(nèi)存分配策略,日志閱讀,一些常見名詞和提供的一些性能監(jiān)控工具。內(nèi)存分配與回收策略對(duì)象優(yōu)先在分配大多數(shù)情況下,對(duì)象優(yōu)先在新生代區(qū)中分配。當(dāng)區(qū)域沒有足夠空間進(jìn)行分配時(shí),將發(fā)生一次。

概述

本篇旨在講清楚jvm的內(nèi)存分配策略,gc日志閱讀,一些常見名詞和jdk提供的一些性能監(jiān)控工具。廢話不多說,開始上貨。

GC日志閱讀

在開發(fā)的世界里,閱讀日志是最基礎(chǔ)的能力,也是解決問題重要的工具。同樣閱讀gc日志也是解決虛擬機(jī)內(nèi)存的基礎(chǔ)技能,通過配置參數(shù)-XX:+PrintGCDetails就可以打印gc日志,建議加上參數(shù)-Xloggc指定gc日志目錄,避免gc日志和console控制臺(tái)日志混亂造成的閱讀困難。
每一種收集器的日志都會(huì)略有不同,但會(huì)維持一定的共性,以下面一段日志為例:

0.332: [GC (Allocation Failure) [PSYoungGen: 6120K->504K(6144K)] 12535K->12549K(19968K), 0.0066909 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.339: [Full GC (Ergonomics) [PSYoungGen: 504K->0K(6144K)] [ParOldGen: 12045K->10615K(13824K)] 12549K->10615K(19968K), [Metaspace: 3473K->3473K(1056768K)], 0.1372999 secs] [Times: user=0.28 sys=0.00, real=0.14 secs] 

最前面的0.332和0.339代表了gc的發(fā)生的時(shí)間,它的含義是表達(dá)虛擬機(jī)啟動(dòng)到發(fā)生gc的秒數(shù)。后面的GC和Full GC代表著垃圾收集的停頓類型,如果是GC代表的是新生代的GC,也稱ygc和minor gc,fullgc代表的是對(duì)整堆的一個(gè)gc。后面括號(hào)里的Allocation Failure和Ergonomics代表的是發(fā)生gc的原因,分別是eden區(qū)域空間不夠和parOldGen空間不夠?qū)е碌膅c和fullgc問題。以Full GC為例,接下來(lái)的[PSYoungGen、[ParOldGen、[Metaspace代表gc發(fā)生的區(qū)域,分別是年輕代、老年代、元空間,其名字也是由所使用的gc收集器密切相關(guān),大致如下:

收集器                    顯示區(qū)域
serial                   DefNew
ParNew                   ParNew
Parallel Scavenge        PSYoungGen
serial old               Tenured
parallel old             ParOldGen
CMS                      CMS

后面方括號(hào)內(nèi)部的 504K->0K(6144K)代表著該區(qū)域GC前使用容量-》GC后該區(qū)域所使用容量(該區(qū)域總?cè)萘浚?,方括?hào)之外的12549K->10615K(19968K)則代表gc之前堆中使用容量-》gc后堆中使用容量(堆總?cè)萘浚?.1372999 secs這個(gè)很簡(jiǎn)單,代表gc占用時(shí)間,單位是秒。

內(nèi)存分配與回收策略

對(duì)象優(yōu)先在Eden分配
大多數(shù)情況下,對(duì)象優(yōu)先在新生代Eden區(qū)中分配。當(dāng)Eden區(qū)域沒有足夠空間進(jìn)行分配時(shí),將發(fā)生一次Minor GC。虛擬機(jī)提供了-XX:+PrintGCDetails用來(lái)輸出gc日志,此日志會(huì)告訴我們垃圾收集行為時(shí)的內(nèi)存日志,并在進(jìn)程結(jié)束后輸出當(dāng)前內(nèi)存各區(qū)域的分配情況。上例子:

public class TestAllocation {

    private static final int _1MB=1024*1024;

    public static void main(String[] args) {
        byte[] a1,a2,a3,a4;
        a1=new byte[2*_1MB];
        a2=new byte[2*_1MB];
        a3=new byte[2*_1MB];
        a4=new byte[4*_1MB];
    }
}

gc日志如下所示:

"C:Program FilesJavajdk1.8.0_151injava" -XX:+PrintGCDetails -Xmx20m -Xms20m -Xmn10m 
[GC (Allocation Failure) [PSYoungGen: 6294K->808K(9216K)] 6294K->4912K(19456K), 0.0023349 secs] [Times: user=0.09 sys=0.00, real=0.02 secs] 
Heap
 PSYoungGen      total 9216K, used 7273K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc50670,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)
 Metaspace       used 3473K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 381K, capacity 388K, committed 512K, reserved 1048576K

其中vm配置參數(shù)從第一行便可知。新生代分為eden區(qū)域和兩塊survior區(qū)域,默認(rèn)比例為8:1:1,從圖中eden:from:to=8192:1024:1024可以得到驗(yàn)證。下來(lái)我們就根據(jù)gc日志分析下在執(zhí)行這段程序時(shí),jvm究竟都做了哪些事。

從這張圖片可知,在jdk1.8.0_151中,即使跑一個(gè)空的main函數(shù),新生代就要占2362k,這個(gè)是虛擬機(jī)的初始內(nèi)存占用,好奇寶寶可以通過jmap命令看看到底堆里裝了什么。現(xiàn)在讓我們回到最開始代碼中,會(huì)將a1、a2分配在新生代的eden區(qū),此時(shí)eden區(qū)域?yàn)?048k+2048K+2362k=6458k,因?yàn)閑den區(qū)域空間不夠,不足以將a3裝入,此時(shí)觸發(fā)minor gc,又因?yàn)榇藭r(shí)a1、a2對(duì)象還存活,suivor區(qū)域只有1024k,故將a1、a2分配擔(dān)保到老年代。從日志中可知,經(jīng)歷過一次minor gc新生代還有808k的存活對(duì)象,因?yàn)閍1、a2已經(jīng)擔(dān)保到老年代,故這是初始內(nèi)存中經(jīng)過gc存活的對(duì)象,通過復(fù)制算法轉(zhuǎn)移到survivor中。此時(shí)eden區(qū)域是0k,其中一塊survivor是初始內(nèi)存,老年代存放著a1、a2對(duì)象,此時(shí)開始繼續(xù)分配對(duì)象內(nèi)存,因a3+a4

大對(duì)象直接進(jìn)入老年代
哪怕你從來(lái)沒有學(xué)習(xí)過jvm知識(shí),你或許也聽說過江湖上流傳著大對(duì)象直接進(jìn)入老年代這個(gè)傳聞。很多人都知道這個(gè)知識(shí)點(diǎn),但恐怕大多數(shù)人并不能準(zhǔn)確的去描述這個(gè)分配策略。
1.何謂大對(duì)象?
所謂大對(duì)象就是需要大量連續(xù)內(nèi)存空間的對(duì)象,上個(gè)例子中的byte數(shù)組就是典型的大對(duì)象。
2.參數(shù)-XX:PretenureSizeThreshold的作用?
虛擬機(jī)提供了-XX:PretenureSizeThreshold,令大于這個(gè)值得對(duì)象直接在老年代分配。hotspot可以在年輕代手機(jī)內(nèi)存的收集器有Serial、ParNew、Parallel Scavenge以及G1(G1劃分內(nèi)存區(qū)域比較特殊暫不考慮)。其中只有Serial和ParNew收集器可以識(shí)別這個(gè)參數(shù),Parallel Scavenge是不識(shí)別這個(gè)參數(shù)的,但并不是大對(duì)象直接進(jìn)入老年代分配策略對(duì)其就是無(wú)效的,在Parallel Scavenge中自有它的實(shí)現(xiàn),大約等于Eden區(qū)域一半的對(duì)象會(huì)被認(rèn)成大對(duì)象。感興趣的可以來(lái)這看看,傳送門:鏈接描述.如果想要使用-XX:PretenureSizeThreshold參數(shù),可以考慮使用ParNew+CMS的組合。給大家展示一個(gè)例子:

    public class BigObject {

    public static void main(String[] args) {
        byte[] test = new byte[4*1024*1024];
    }
}


從gc日志,我們很容易得出大對(duì)象進(jìn)入老年代這個(gè)結(jié)論。對(duì)了,還需要注意的是XX:PretenureSizeThreshold的單位是k,不能像-Xmx3mb這樣直接指定。
3.為什么大對(duì)象要進(jìn)入老年代?
在搞清楚這個(gè)問題之前,我們首先要去揣摩大師們?cè)O(shè)計(jì)分代算法的意圖。設(shè)計(jì)師們希望新生代的對(duì)象多數(shù)是朝生夕滅的,故新生代采用復(fù)制算法最合適。復(fù)制算法的優(yōu)點(diǎn)是簡(jiǎn)單,速度快(在存活對(duì)象少的情況下),缺點(diǎn)是占內(nèi)存要發(fā)生內(nèi)存復(fù)制。這樣做的目的就是避免在eden區(qū)和兩個(gè)survivor區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。

長(zhǎng)期存活的對(duì)象將進(jìn)入老年代
虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡計(jì)數(shù)器,保存在對(duì)象頭中的Mark word部分。如果對(duì)象在eden出生,經(jīng)歷過一次minor gc仍然活著,并且能被survivor區(qū)容納,將會(huì)被移動(dòng)到survivor區(qū)域,并且將gc年齡設(shè)置為1,這種對(duì)象沒經(jīng)歷一次Minor gc ,年齡就增加一歲,當(dāng)它的年齡增加到一定程度(默認(rèn)是15歲),就會(huì)被晉升到老年代,這個(gè)年齡閾值可以通過參數(shù)-XX:MaxTenuringThresold來(lái)設(shè)置.

動(dòng)態(tài)對(duì)象年齡判定
虛擬機(jī)并不是永遠(yuǎn)要求對(duì)象的年齡永遠(yuǎn)達(dá)到MaxTenuringThresold才能晉升老年代,如果在survivor空間中相同年齡所有的對(duì)象的大小總和大于survivor空間的一半,年齡大于或等于改年齡的對(duì)象直接進(jìn)入老年代,無(wú)須等到MaxTenuringThresold要求的年齡。

空間分配擔(dān)保
在發(fā)生minor gc之間,虛擬機(jī)會(huì)先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對(duì)象總空間,如果條件成立,則代表這次gc是安全的。如果不成立,jdk1.7和jdk1.8的版本中會(huì)繼續(xù)檢查老年代最大的可用空間是否大于歷次晉升到老年代對(duì)象的平均大小,如果小于則進(jìn)行一次full gc,如果大于則嘗試進(jìn)行一次minor gc,如果出現(xiàn)老年代擔(dān)保失敗的情況則會(huì)進(jìn)行一次full gc。

性能監(jiān)控與故障處理工具

給一個(gè)系統(tǒng)定位問題的時(shí)候,知識(shí)、經(jīng)驗(yàn)是關(guān)鍵基礎(chǔ),數(shù)據(jù)是依據(jù),工具是運(yùn)用知識(shí)處理數(shù)據(jù)的手段。java開發(fā)程序員應(yīng)該都知道jdk的bin目錄下有java.exe和javac.exe,但其實(shí)bin下面還有很多的小工具都極其實(shí)用,是我們排查問題的關(guān)鍵。工具很多,我們挑幾個(gè)最常用的來(lái)說明:

jstat

可以用來(lái)監(jiān)視虛擬機(jī)各種運(yùn)行時(shí)狀態(tài)信息的命令行工具。jstat格式命令為:

jstat [ option vmid [interval[s|ms] [count]] ]

option代表我們想要查詢的虛擬機(jī)信息,vmid就是我們的進(jìn)程id,interval和count代表查詢間隔(默認(rèn)單位是ms)和次數(shù)。jstat工具主要選項(xiàng)如下圖所示:

gccause是最常用的一個(gè)option之一,假如我們需要每250ms查詢一次進(jìn)程5888的垃圾收集情況,一共查詢20次,命令應(yīng)該為:

S0和S1對(duì)應(yīng)的是新生代的兩塊suivor區(qū)域,E對(duì)應(yīng)的是Eden,O對(duì)應(yīng)的是老年代,M對(duì)應(yīng)的是Klass Metaspace以及Noklass Metaspace兩者總共的使用率,CCS對(duì)應(yīng)的是NoKlass Metaspace的使用率,YGC表示的是新生代gc發(fā)生的次數(shù),YGCT表示的是新生代gc總共的stop the world的時(shí)間,F(xiàn)GC表示的是Full gc的次數(shù),F(xiàn)GCT GCT同YGCT一樣就不多說了,LGCC表示上次gc的原因,GCC表示此次gc的原因。需要額外注意的是,當(dāng)使用CMS作為老年代收集器的時(shí)候,每執(zhí)行一次Old GC,F(xiàn)GC就會(huì)增加兩次。

jinfo

:可以用來(lái)實(shí)時(shí)查看和調(diào)整虛擬機(jī)的各項(xiàng)參數(shù)。
使用jps -v pid可以查看虛擬機(jī)啟動(dòng)時(shí)顯示指定的參數(shù),前提是你要開rmi。如果想要查看未被指定參數(shù)的默認(rèn)值,除了查文檔就只能通過jinfo -flag 選項(xiàng)進(jìn)行查詢,當(dāng)然如果你使用java -XX:+PrintFlagsFinal查看默認(rèn)值也是一個(gè)很好的選擇(此命令會(huì)打印出所有的默認(rèn)值),同時(shí)你還可以通過jinfo -flag [+|-] name=value或者-flag name=value修改一部分運(yùn)行期可寫的虛擬機(jī)參數(shù),如果想要查看那些事運(yùn)行期可寫的參數(shù),可以通過命令java -XX:+PrintFlagsFinal |grep manageable查詢。

jmap

jmap命令主要用于生成堆轉(zhuǎn)儲(chǔ)快照,一般稱為dump文件。當(dāng)然它的作用不僅僅只有這個(gè),還有查詢java堆和方法區(qū)的詳細(xì)信息.生成dump文件。其使用方法如下:

生成堆轉(zhuǎn)儲(chǔ)快照: jmap -dump:format=b,file=gc.bin pid(線上慎用,如果堆文件較大,會(huì)比較耗時(shí),因?yàn)橐WCdump的準(zhǔn)確性,會(huì)發(fā)生stop the world)
查看堆詳細(xì)信息,使用回收期、參數(shù)配置和分代狀況等:jmap -heap pid
查看對(duì)象統(tǒng)計(jì)信息:jmap -histo pid(如果加上參數(shù):live,jmap -histo:live pid會(huì)率先執(zhí)行一次gc,線上慎用)

jhat

jhat命令可與jmap搭配使用,用來(lái)分析dump文件,其內(nèi)置了一個(gè)http服務(wù)器,生成分析結(jié)果,可以在瀏覽器查看。不過一般都不會(huì)用jhat來(lái)分析,原因有兩點(diǎn)1:不會(huì)直接在部署服務(wù)器上分析,因?yàn)榉治龉ぷ魇且粋€(gè)耗時(shí)且消耗硬件資源的過程。2:因?yàn)閖hat分析確實(shí)比較簡(jiǎn)陋,目前eclispe的mat是分析dump文件最專業(yè)的工具,可以到eclispe官網(wǎng)下載插件版,無(wú)須安裝eclispe。

jstack

jstack命令用于生成虛擬機(jī)當(dāng)前時(shí)刻的線程快照,一般稱為threaddump或javacore文件。線程快照就是當(dāng)前虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合,主要用來(lái)定位線程出現(xiàn)長(zhǎng)時(shí)間停頓的原因,如線程間死鎖、死循環(huán)、請(qǐng)求外部資源長(zhǎng)時(shí)間等待等都是導(dǎo)致線程長(zhǎng)時(shí)間停頓的主要原因。

在jdk1.5中, Thread類新增了一個(gè)getAllStackTraces()方法用于獲取虛擬機(jī)中所有的StackTraceElement對(duì)象,使用這個(gè)方法可以完成jstack的大部分功能,可以在實(shí)際的項(xiàng)目中用這個(gè)方法做個(gè)管理頁(yè)面,來(lái)隨時(shí)監(jiān)控線程堆棧。

VisualVM

VisualVmM是jdk發(fā)布到目前為止,最強(qiáng)大的運(yùn)行監(jiān)視和故障處理數(shù)據(jù),他有一個(gè)很大的優(yōu)點(diǎn)不需要被監(jiān)視的程序基于特殊的agent運(yùn)行,因此它對(duì)應(yīng)用程序地實(shí)際性能影響很小,使得它可以直接應(yīng)用到生產(chǎn)環(huán)境中。它上面有許多好玩的插件,比如Btrace,它可是線上調(diào)試的神奇,可以在不停止目標(biāo)程序運(yùn)行的前提下,通過hotspot的hotswap技術(shù)動(dòng)態(tài)加入原本不存在的調(diào)試代碼。這個(gè)插件等以后有機(jī)會(huì)了再具體介紹下。

總結(jié)

基本上,hotspot系列jvm的理論知識(shí)和常用性能監(jiān)控工具已經(jīng)介紹完畢,但這些知識(shí)只是jvm世界的一點(diǎn)皮毛,如果大家想要學(xué)習(xí)更多的知識(shí),可以去關(guān)注R大,被稱為jvm源碼化身的男人。傳送門:https://www.zhihu.com/people/...。另外阿里的你假笨同學(xué)開發(fā)了兩個(gè)特別實(shí)用的程序,微信小程序JVMPocket和網(wǎng)站:http://xxfox.perfma.com/,至于它們有什么功效,大家自己去體驗(yàn)吧^_^。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/69040.html

相關(guān)文章

  • 聊聊企業(yè)級(jí) Java 應(yīng)用最重要的4個(gè)性能指標(biāo)

    摘要:筆者多次參與銀行運(yùn)營(yíng)商等大型企業(yè)的性能優(yōu)化工作總結(jié)了企業(yè)級(jí)應(yīng)用最應(yīng)重視的個(gè)性能指標(biāo),主要包括商業(yè)事務(wù),外部服務(wù),垃圾回收以及應(yīng)用布局。應(yīng)用布局最后要探討的性能指標(biāo)是應(yīng)用布局。另一個(gè)需要監(jiān)測(cè)的是容器性能。 雖然很多人都曾預(yù)言 Java 將一蹶不振,但是不可否認(rèn)的是,很多重要項(xiàng)目中,尤其是銀行和政府一些大型項(xiàng)目,Java 仍在其中扮演著極其重要的角色。筆者多次參與銀行、運(yùn)營(yíng)商等大型企業(yè)的性...

    sherlock221 評(píng)論0 收藏0
  • 系統(tǒng)優(yōu)化怎么做-JVM優(yōu)化之開篇

    摘要:幾個(gè)死鎖場(chǎng)景兩個(gè)線程相互調(diào)用導(dǎo)致互相等待同步結(jié)束。線程為了檢測(cè)死鎖,它需要遞進(jìn)地檢測(cè)所有被請(qǐng)求的鎖。思考題線程有哪些狀態(tài)這些線程大多處于什么樣的狀態(tài)分布我們可以稱系統(tǒng)運(yùn)行是健康的。 前言 在上一期Tomcat優(yōu)化中,針對(duì)JVM相關(guān)主要參數(shù)做過一定說明,這一期主要介紹進(jìn)行一些概念及經(jīng)驗(yàn)。后面分章節(jié)去講述相關(guān)工具的基本使用。 優(yōu)化優(yōu)先級(jí) 整體來(lái)講,系統(tǒng)優(yōu)化應(yīng)先優(yōu)化架構(gòu)及代碼,來(lái)解決具體功能...

    gecko23 評(píng)論0 收藏0
  • Android內(nèi)存泄漏總結(jié)

    摘要:內(nèi)存泄漏總結(jié)內(nèi)存管理的目的就是讓我們?cè)陂_發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。在中,內(nèi)存泄漏的范圍更大一些。 Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們?cè)陂_發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏大家都不陌生了,簡(jiǎn)單粗俗的講,就是該被釋放的對(duì)象沒有釋放,一直被某個(gè)或某些實(shí)例所持有卻不再被使用導(dǎo)致 GC 不能回收。最近自己閱讀了大量相關(guān)的文檔資料,打...

    legendaryedu 評(píng)論0 收藏0
  • 內(nèi)存泄露從入門到精通三部曲之基礎(chǔ)知識(shí)篇

    摘要:騰訊特約作者姚潮生首先以一個(gè)內(nèi)存泄露實(shí)例來(lái)開始本節(jié)基礎(chǔ)概念的內(nèi)容。堆內(nèi)存用于存放所有由創(chuàng)建的對(duì)象內(nèi)容包括該對(duì)象其中的所有成員變量和數(shù)組。回到我們的問題,為什么內(nèi)存會(huì)泄露堆內(nèi)存中的長(zhǎng)生命周期的對(duì)象持有短生命周期對(duì)象的強(qiáng)軟引用,盡管 騰訊Bugly特約作者: 姚潮生 首先以一個(gè)內(nèi)存泄露實(shí)例來(lái)開始本節(jié)基礎(chǔ)概念的內(nèi)容。 實(shí)例1:?jiǎn)卫龑?dǎo)致內(nèi)存對(duì)象無(wú)法釋放而泄露 showImg(http://i....

    nicercode 評(píng)論0 收藏0
  • [譯]GC專家系列5-Java應(yīng)用性能優(yōu)化的原則

    摘要:在本文中我將會(huì)介紹應(yīng)用性能優(yōu)化的一般原則。性能優(yōu)化的流程圖摘取自和合著的性能,描述了應(yīng)用性能優(yōu)化的處理流程。例如,對(duì)每臺(tái)服務(wù)器,你面臨著為單個(gè)分配堆內(nèi)存和運(yùn)行個(gè)并為每個(gè)分配堆內(nèi)存的選擇。不過位能使用堆內(nèi)存最大理論值只有。 原文鏈接:http://www.cubrid.org/blog/dev-platform/the-principles-of-java-application-per...

    lufficc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<