国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
一步步優(yōu)化JVM<四>:決定Java堆的大小以及內(nèi)存占用
   到目前為止,還沒有做明確的優(yōu)化工作。只是做了初始化選擇工作,比如說(shuō):JVM部署模型、JVM運(yùn)行環(huán)境、收集哪些垃圾回收器的信息以及需要遵守垃圾回收原則。這一步將介紹如何評(píng)估應(yīng)用需要的內(nèi)存大小以及Java堆大小。首先需要判斷出應(yīng)用存活的數(shù)據(jù)的大小,存活數(shù)據(jù)的大小是決定配置應(yīng)用需要的Java堆大小的重要條件,也能夠決定是否需要重新審視一下應(yīng)用的內(nèi)存需求或者修改應(yīng)用程序以滿足內(nèi)存需求。

   注意:存活數(shù)據(jù)是指,應(yīng)用處于穩(wěn)定運(yùn)行狀態(tài)下,在Java堆里面長(zhǎng)期存活的對(duì)象。換一句話說(shuō),就是應(yīng)用在穩(wěn)定運(yùn)行的狀態(tài)下,F(xiàn)ull GC之后,Java堆的所占的空間。

約束
   有多少物理內(nèi)存可以供JVM使用?是部署多個(gè)JVM或者單個(gè)JVM?對(duì)做出的決定有重要影響。下面列出了一些要點(diǎn)可以幫助決定有多少物理內(nèi)存可以供使用。
   1、一個(gè)機(jī)器上面只是部署一個(gè)JVM,且就一個(gè)應(yīng)用使用?如果是這種情況,那么機(jī)器的所有物理內(nèi)存可以供JVM使用。
   2、一個(gè)機(jī)器上部署了多個(gè)JVM?或者一個(gè)機(jī)器上部署了多個(gè)應(yīng)用?如果是這兩個(gè)中的任何一種情況,你就必須要決定每一個(gè)JVM或者應(yīng)用需要分配多少內(nèi)存了。
   無(wú)論是前面的哪種情況,都需要給操作系統(tǒng)留出一些內(nèi)存。
HotSpot VM的堆結(jié)構(gòu)
   在做內(nèi)存占用測(cè)量之前,我們必須要先理解HotSpot VM Java堆的結(jié)構(gòu),理解這個(gè)對(duì)決定應(yīng)用需要的Java堆大小以及優(yōu)化垃圾收器性能有很好的幫助。
HotSpot VM有3個(gè)主要的空間:young代、old代以及permanent代,如上圖所示。

   當(dāng)Java應(yīng)用分配Java對(duì)象時(shí),這些對(duì)象被分配到y(tǒng)oung代。在經(jīng)歷過(guò)幾次minor GC之后,如果對(duì)象還是存活的,就會(huì)被轉(zhuǎn)移到old代空間。permanent代空間存儲(chǔ)了VM和Java類的元數(shù)據(jù)比如內(nèi)置的字符串和類的靜態(tài)變量。

   -Xmx和-Xms這個(gè)兩個(gè)命令行選項(xiàng)分別指定yound代加上old代空間的總和的初始最大值和最小值,也就是Java堆的大小。當(dāng)-Xms的值小于-Xmx的值的時(shí)候,Java堆的大小可以在最大值和最小值之前浮動(dòng)。當(dāng)Java應(yīng)用強(qiáng)調(diào)吞吐量和延遲的時(shí)候,傾向于把-Xms和-Xmx設(shè)置成相同的值,由于調(diào)整young代或者old代的大小都需要進(jìn)行Full GC,F(xiàn)ull GC降低吞吐量以及加強(qiáng)延遲。

   young代的空間可以通過(guò)下面的任意一個(gè)命令行選項(xiàng)來(lái)設(shè)置:
  1. 1、-XX:NewSize=<n>[g|m|k]    

 young代的初始值和最小值。<n>是大小,[g|m|k]表示單位是G字節(jié),M字節(jié)或者千字節(jié)。young代的大小不會(huì)小于這個(gè)值。當(dāng)設(shè)定-XX:NewSize=<n>[g|m|k]的時(shí)候,-XX:MaxNewSize=<n>[g|m|k]需要被指定。
  1. 2、-XX:MaxNewSize=<n>[g|m|k]  

young區(qū)空間的最大值。同上面反過(guò)來(lái),當(dāng)指定-XX:MaxNewSize=<n>[g|m|k]的需要指定-XX:NewSize=<n>[g|m|k]。
  1. 3、-Xmn<n>[g|m|k]   

 直接指定young代的初始值、最小值以及最大值。也就是說(shuō),young區(qū)的大小被固定成這個(gè)值了。這個(gè)值用來(lái)鎖定young代的大小很方便。

   有一點(diǎn)需要注意的是,如果-Xms和-Xmx沒有被設(shè)定成相同的值,而且-Xmn被使用了,當(dāng)調(diào)整Java堆的大小的時(shí)候,不會(huì)調(diào)整young代的空間大小,young代的空間大小會(huì)保持恒定。因此,-Xmn應(yīng)該在-Xms和-Xmx設(shè)定成相同的時(shí)候才指定。

   old代的空間大小可以基于young代的大小進(jìn)行計(jì)算,old代的初始值的大小是-Xms的值減去-XX:NewSize,最大值是-Xmx減去-XX:MaxNewSize,如果-Xmx和-Xms設(shè)置成了相同的值,而且使用-Xmn選項(xiàng)或者-XX:NewSize和-XX:MaxNewSize設(shè)置成了相同的值,那么old代的大小就是-Xmx減去-Xmn。
   permanent代的大小通過(guò)下面命令行參數(shù)指定
  1. 1、-XX:PermSize=<n>[g|m|k]   

 表示permanent代的初始值和最小值,n表示數(shù)值,g|m|k表示單位、permanent的空間一定不會(huì)比這個(gè)空間小。
  1. 2、-XX:MaxPermSize=<n>[g|m|k]  

   permanent代的最大值,permanent代的大小不會(huì)超過(guò)這個(gè)值。

   Java應(yīng)用應(yīng)該指定這兩個(gè)值成為同一個(gè)值,由于這個(gè)值的調(diào)整會(huì)導(dǎo)致Full GC。

   如果上面提到的Java堆大小、young代、permanent代的大小都沒有指定,那么JVM會(huì)根據(jù)應(yīng)用的情況自行計(jì)算。

   在young代、old代以及permanent代中任何一個(gè)空間里面無(wú)法分配對(duì)象的時(shí)候就會(huì)觸發(fā)垃圾回收,理解這點(diǎn),對(duì)后面的優(yōu)化非常重要。當(dāng)young代沒有足夠空間分配Java對(duì)象的時(shí)候,觸發(fā)minor GC。minor GC相對(duì)于Full GC來(lái)說(shuō)會(huì)更短暫。

   一個(gè)對(duì)象在經(jīng)歷過(guò)一定次數(shù)的Minor GC之后,如果還存活,那么會(huì)被轉(zhuǎn)移到old代(對(duì)象有一個(gè)“任期閥值”的概念,優(yōu)化延遲的時(shí)候再介紹)。當(dāng)old代沒有足夠空間放置對(duì)象的時(shí)候,HotSpot VM觸發(fā)full GC。實(shí)際上在進(jìn)行Minor GC的時(shí)候發(fā)現(xiàn)沒有old代足夠的空間來(lái)進(jìn)行對(duì)象的轉(zhuǎn)移,就會(huì)觸發(fā)FullGC,相對(duì)于在MinorGC的過(guò)程中發(fā)現(xiàn)對(duì)象的移動(dòng)失敗了然后觸發(fā)FullGC,這樣的策略會(huì)有更小的花費(fèi)。當(dāng)permanent代的空間不夠用的時(shí)候的,也會(huì)觸發(fā)FullGC。

   如果FullGC是由于old代滿了而觸發(fā)的,old代和permanent代的空間都會(huì)被垃圾回收,即使permanent代的空間還沒有滿。同理,如果FullGC是由于permanent代滿了而觸發(fā)的,old代和permanent代的空間都會(huì)被垃圾回收,即使old代的空間還沒有滿。另外,young代同樣會(huì)被垃圾回收,除非-XX:+ScavengeBeforeFullGC選項(xiàng)被指定了,-XX:+ScavengeBeforeFullGC關(guān)閉FullGC的時(shí)候young代的垃圾回收。

堆大小優(yōu)化的起點(diǎn)
   為了進(jìn)行Java堆大小的優(yōu)化,一個(gè)合適的起點(diǎn)很重要。這節(jié)描述的方案是需要先使用比應(yīng)用需要量更大的Java堆作為開始。這一步的目的是收集一些初始化信息以及為了進(jìn)一步優(yōu)化Java堆大小需要的數(shù)據(jù)。

   就像在“選擇JVM runtime”小節(jié)里面提到過(guò)的,由吞吐量垃圾回收器(throughput garbage collector)開始。記住,使用吞吐量垃圾回收器通過(guò)設(shè)置-XX:+UserParallelOldGC命令行選項(xiàng),如果你使用的HotSpot VM不支持的這個(gè)選項(xiàng),那么就使用-XX:+UserParallelGC。

   如果你能夠準(zhǔn)確的預(yù)估到應(yīng)用需要消耗的Java堆空間,可以通過(guò)設(shè)定-Xmx和-Xms來(lái)作為這個(gè)步驟的起點(diǎn)。如果你不知道該設(shè)定什么值,就讓JVM來(lái)選擇吧,反正后面,都會(huì)根據(jù)實(shí)際情況進(jìn)行優(yōu)化調(diào)整。

   關(guān)于如何監(jiān)控GC日志前面的“GC優(yōu)化基礎(chǔ)”已經(jīng)描述過(guò)了。GC日志會(huì)展示在使用中的java堆的大小。初始化和最大的堆大小可以通過(guò)-XX:+PrintCommandLineFlags來(lái)查看。-XX:+PrintCommandLineFlags打印出在HotSpot VM初始化的時(shí)候選擇的初始值和最大值比如-XX:InitialHeapSize=<n> -XX:MaxHeapSize=<m>,這里n表示初始化的java堆大小值,m表示java堆的最大值。

   不管你是指定java堆的大小還是使用默認(rèn)的大小,必須讓應(yīng)用進(jìn)入穩(wěn)定運(yùn)行的狀態(tài),你必須要有能力和手段讓應(yīng)用處于和線上穩(wěn)定運(yùn)行的狀態(tài)相同的狀態(tài)。

   如果在企圖讓應(yīng)用進(jìn)入穩(wěn)定狀態(tài)的時(shí)候,你在垃圾回收日志里面觀察到OutOfMemoryError,注意是old代溢出還是permanent代溢出。下面一個(gè)old代溢出的例子:
  1. 2012-07-15T18:51:03.895-0600: [Full GC[PSYoungGen: 279700K->267300K(358400K)]  
  2. [ParOldGen: 685165K->685165K(685170K)]  
  3. 964865K->964865K(1043570K)  
  4. [PSPermGen: 32390K->32390K(65536K)],0.2499342 secs]  
  5. [Times: user=0.08 sys=0.00, real=0.05 secs]  
  6. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  

   上面重要的部分加粗標(biāo)示了,由于使用的是吞吐量垃圾回收器,old代的統(tǒng)計(jì)信息標(biāo)示為ParOldGen。這行表示了old代的在FullGC的時(shí)候占用的空間。從這個(gè)結(jié)果來(lái)看,可以得出的結(jié)論是old代的空間太小了,由于FullGC前后old代的被占用的空間和分配的空間基本相等了,因此,JVM報(bào)了OutOfMemoryError。相比較,通過(guò)PSPermGen這行可以看出permanent代的空間占用是32390K,和他的容量(65536K)比還是有一定的距離。
下面的例子展示了由于permanent太少了而導(dǎo)致的OutOfMemoryError發(fā)生的例子
  1. 2012-07-15T18:26:37.755-0600: [Full GC  
  2.   [PSYoungGen: 0K->0K(141632K)]  
  3.   [ParOldGen: 132538K->132538K(350208K)]  
  4.   32538K->32538K(491840K)  
  5.   [PSPermGen: 65536K->65536K(65536K)],  
  6.   0.2430136 secs]  
  7.   [Times: user=0.37 sys=0.00, real=0.24 secs]  
  8.   java.lang.OutOfMemoryError: PermGen space  

   同上面一樣,把關(guān)鍵行標(biāo)示出來(lái)了,通過(guò)PSPermGen這行可以看出在FullGC前后,他的空間占用量都和他的容量相同,可以得出的結(jié)論是permanent代的空間條小了,這樣就導(dǎo)致了OutOfMemoryError。在這個(gè)例子里面,old的占用空間(132538K)遠(yuǎn)比他的容量(350208K)小。

   如果在垃圾回收日志中觀察到OutOfMemoryError,嘗試把Java堆的大小擴(kuò)大到物理內(nèi)存的80%~90%。尤其需要注意的是堆空間導(dǎo)致的OutOfMemoryError以及一定要增加空間。比如說(shuō),增加-Xms和-Xmx的值來(lái)解決old代的OutOfMemoryError,增加-XX:PermSize和-XX:MaxPermSize來(lái)解決permanent代引起的OutOfMemoryError。記住一點(diǎn)Java堆能夠使用的容量受限于硬件以及是否使用64位的JVM。在擴(kuò)大了Java堆的大小之后,再檢查垃圾回收日志,直到?jīng)]有OutOfMemoryError為止。

   如果應(yīng)用運(yùn)行在穩(wěn)定狀態(tài)下沒有OutOfMemoryError就可以進(jìn)入下一步了,計(jì)算活動(dòng)對(duì)象的大小。
計(jì)算活動(dòng)對(duì)象的大小
   就像前面提到的,活動(dòng)對(duì)象的大小是應(yīng)用處于穩(wěn)定運(yùn)行狀態(tài)時(shí),長(zhǎng)時(shí)間存活數(shù)據(jù)占用的Java堆的空間大小。換句話說(shuō),就是應(yīng)用穩(wěn)定運(yùn)行是,在FullGC之后,old代和permanent代的空間大小。

   活動(dòng)對(duì)象的大小可以通過(guò)垃圾回收日志查看,它提供了一些優(yōu)化信息,如下:
   1、應(yīng)用處于穩(wěn)定運(yùn)行狀態(tài)下,old代的Java堆空間占用數(shù)量。
   2、應(yīng)用處于穩(wěn)定運(yùn)行狀態(tài)下,permanent代的Java堆空間占用數(shù)量。

   為了保證能夠準(zhǔn)確的評(píng)估應(yīng)用的活動(dòng)對(duì)象大小,最好的做法是多看幾次FullGC之后Java堆空間的大小,保證FullGC是發(fā)生在應(yīng)用處于穩(wěn)定運(yùn)行的狀態(tài)。

   如果應(yīng)用沒有發(fā)生FullGC或者發(fā)生FullGC的次數(shù)很少,在性能測(cè)試環(huán)境,可以通過(guò)Java監(jiān)控工具來(lái)觸發(fā)FullGC,比如使用VisualVM和JConsole,這些工具在最新的JDK的bin目錄下可以找到,VisualVM集成了JConsole,VisualVM或者JConsole上面有一個(gè)觸發(fā)GC的按鈕。

   另外,jmap命令可以選擇來(lái)強(qiáng)制HotSpot VM進(jìn)行FullGC。jmap 需要-histo:live命令選項(xiàng)以及JVM進(jìn)程id。JVM的進(jìn)程id可以通過(guò)jps命令獲取。比如JVM的進(jìn)程id是348,jmap命令用來(lái)觸發(fā)FullGC可以想如下這樣寫:
  1. $ jmap -histo:live 348  

   jmap不僅僅觸發(fā)FullGC,而且產(chǎn)生堆的關(guān)于對(duì)象分配的概要信息。不過(guò)就目前這步的目的而言,可以忽略產(chǎn)生的堆概要信息。

初始化堆大小配置
   本節(jié)描述了怎樣利用活動(dòng)對(duì)象的大小來(lái)決定初始化的Java堆的大小。下面的圖,給出了應(yīng)用存活的對(duì)象的大小。比較明智的做法是多收集幾次FullGC信息,有更多的信息,能夠做出更加好的決定。
   通過(guò)活動(dòng)對(duì)象大小的信息,可以做出關(guān)于Java堆的大小有根據(jù)的決定,以及可以估計(jì)出最壞情況下會(huì)導(dǎo)致的延遲。

   比較常規(guī)是,Java堆大小的初始化值和最大值(通過(guò)-Xms和-Xmx選項(xiàng)來(lái)指定)應(yīng)該是old代活動(dòng)對(duì)象的大小的3到4倍。

   在上圖中顯示的FullGC信息中,在FullGC之后old代的大小是295111K,差不多是295M,即活動(dòng)的對(duì)象的大小是295M。因此,推薦的Java堆的初始化和最大值應(yīng)該是885M到1180M,即可以設(shè)置為-Xms885m -Xmx1180m。在這個(gè)例子中,Java堆的大小是1048570K差不多1048M,在推薦值范圍內(nèi)。

   另外一個(gè)常規(guī)是,permanent的初始值和最大值(-XX:PermSize和-XX:MaxPermSize)應(yīng)該permanent代活動(dòng)對(duì)象大小的1.2到1.5倍。在上圖中看到在FullGC之后permanent代占用空間是32390K,差不多32M。因此,permanent代的推薦大小是38M到48M,即可以設(shè)置為-XX:PermSize=48m -XX:MaxPermSize=48m(1.5倍)。這個(gè)例子里面,permanent代的空間大小是65536K即64M,大出了17M,不過(guò)在1G內(nèi)存的系統(tǒng)的中,這個(gè)數(shù)值完全可以忍受。

   另外一個(gè)常規(guī)是,young代空間應(yīng)該是old代活動(dòng)對(duì)象大小的1到1.5倍。那么在這里例子中,young代的大小可以設(shè)置為295M到442M。本例里面,young代的空間大小的358400K,差不多358M,在推薦值中間。

   如果推薦的Java堆的初始值和最大值是活動(dòng)對(duì)象大小3到4倍,而young代的推薦只是1到1.5倍,那么old代空間大小應(yīng)該是2到3倍。

   通過(guò)以上規(guī)則,我們可以使用的Java命令可以是這樣的:
  1. java -Xms1180m -Xmx1180m -Xmn295m -XX:PermSize=48m -XX:MaxPermSize=48m  

另外一些考慮
   本節(jié)將提及到在進(jìn)行應(yīng)用內(nèi)存占用評(píng)估的時(shí)候,另外一些需要記住的點(diǎn)。首先,必須要知道,前面只是評(píng)估的Java堆的大小,而不是Java應(yīng)用占用的所有的內(nèi)存,如果要查看Java應(yīng)用占用的所有內(nèi)存在linux下可以通過(guò)top命令查看或者在window下面通過(guò)任務(wù)管理器來(lái)查看,盡管Java堆的大小可能對(duì)Java應(yīng)用占用內(nèi)存做出了最大的貢獻(xiàn)。 比如說(shuō),為了存儲(chǔ)線程堆棧,應(yīng)用需要額外的內(nèi)存,越多的線程,越多內(nèi)存被線程棧消耗,越深的方法間調(diào)用,線程棧越多。另外,本地庫(kù)需要分配額外的內(nèi)存,I/O緩存也需要額外的內(nèi)存。應(yīng)用的內(nèi)存消耗需要評(píng)估到應(yīng)用任何一個(gè)會(huì)消耗內(nèi)存的地方。

   記住,這一步操作不一定能夠滿足應(yīng)用內(nèi)存消耗的需求,如果不能滿足,就回過(guò)頭來(lái)看需求是否合理或者修改應(yīng)用程序。比較可行的一種辦法是修改應(yīng)用程序減小對(duì)象的分配,從而減少內(nèi)存的消耗。
   Java堆的大小計(jì)算僅僅只是開始,根據(jù)需求,在后面的優(yōu)化步驟中可能會(huì)修改。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入探究JVM(2)
JVM系列篇:JVM性能調(diào)優(yōu)的6大步驟,及關(guān)鍵調(diào)優(yōu)參數(shù)詳解
JVM系列(八):堆(Heap)的相關(guān)知識(shí)介紹
JVM參數(shù)調(diào)優(yōu)八大技巧
成為JavaGC專家
Java知識(shí)匯總(游戲&后端)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服