­

JVM內存參數配置

首先我們知道:JVM發生內存錯誤的類型

1、堆內存泄漏:OutOfMemory:Java heap space

此種內存泄漏,增加內存,只能暫時解決問題,並不能根治問題。必須要優化代碼,一定是代碼的問題:排查堆中的大量對象,就會發現,這些對象都被引用,對象不能及時被回收,導致超出了堆的設定最大內存。

2、老年代內存泄漏:OutOfMemoryError:PermGen space

       類名、訪問修飾符、字段描述、方法描述等,所佔空間大於永久代最大值,就會出現,一般都是初始化內存的時候,空間太小,解決辦法是擴大空間

3、棧內存泄漏:StackOverflowError

代碼執行時,代碼進棧,此刻如果棧的內存不足以容納要進棧的代碼的大小空間,那麼久會報該錯誤。可以通過設置棧的空間大小。一般通過:-Xss設置線程的大小來解決。比如:-Xss256m

 

下面進入如何檢測jvm內存情況的實際操作:

1、監控JVM的GC情況

   jstat -gcutil pid 2000 20 (只需要看O,如果達到100%,並且長期處於100%,則代表老年代內存不足)

pid:服務進程的pid,可通過:ps -ef | grep java 來查看java的服務進程pid

2000:每隔多少秒進行監控一次。這裡是2秒

20: 總共獲取20次

E:eden區
O:老年代
P:永久代
YGC:新生代的GC次數
YGCT:當前統計的YGC一共花費的時間(毫秒)
FGC:fullGC老年代的GC次數
FGCT:當前統計的FGC一共花費的時間(毫秒)
GCT:YGC+FGC
 

2、查看jvm配置信息

jmap -head pid  //可以看到java進程的堆的配置信息,各區的空間大小和配置信息

 

3、查看jvm中類和對象的佔用情況 

jmap -histo 5279 | head -20  //查看jvm中各個類的實例數、佔用內存數量以及類的全名

 

4、上面使我們的基本命令使用,那麼我們怎麼預測或者說內存泄漏會有什麼徵兆?

1、tps出現大幅波動,並慢慢降低,甚至降為0,響應時間隨之波動,慢慢升高
2、通過jstat命令看到,Jvm中Old區不斷增加,FullGC非常頻繁,對應的FullGC消耗的時間也不斷增加
3、通過jconsole/jvisualvm可以看到,堆內存曲線不斷上升,接近上限時,變成一條直線
4、日誌報錯java.lang.OutOfMemoryError: Java heap space
 

5、內存泄露怎麼定位?

     (1、確定徵兆:   現象方面,Java進程拋出OOM異常,分析屬於那種異常,是正常的內存資源耗盡還是內存泄漏。

     (2、監控jvm的GC情況:  jstat -gcutil pid 1000 100  (只需要看O,如果達到100%,並且長期處於100%,則代表老年代內存不足) 如果有大量的FGC就要查詢是否有內存泄漏的問題了

     (3、通過jmap命令:jmap -histo pid | head -20,查看當前堆內存中實例數和佔用內存最多的前20個對象
     (4、通過jvisualvm分析定位:
進行遠程堆dump,然後把dump文件下載下來,用jvisualvm打開進行分析,可以看到更直觀的jvm中對象的信息

 

6、下面是進行最後的JVM參數調優:

vm常用參數
—————————————
堆內存 = 年輕代+老年代
年輕代 = Eden+Survivor
Survivor = From Space+To Space
—————————————
年輕代 = Eden+From Space+To Space
堆內存=Eden+From Space+To Space+老年代
====================================

-Xms2048m:初始堆大小,建議<物理內存的1/4,默認值為物理內存的1/64

-Xmx2048m:最大堆大小,建議與-Xms保持一致,默認值為物理內存的1/4

-Xmn512m:新生代大小,建議不超過堆內存的1/2-Xss256k,線程堆棧大小,建議256k

-XX:PermSize=256m:永久代初始值,默認值為物理內存的1/64

-XX:MaxPermSize=256m:永久代最大值,默認值為物理內存的1/4

-XX:SurvivorRatio=8:年輕帶中Eden區和Survivor區的比例,默認為8:1,即Eden(8),FromSpace(1),ToSpace(1)

-XX:MaxTenuringThreshold=15:晉陞到老年代的對象年齡,每個對象堅持過一次MinorGC後對象年齡+1,默認值是15,年齡超過15進入到老年代,該參數在串行GC時有效-

XX:PretenureSizeThreshold=3145728:單位位元組,只對Serial和ParNew兩款收集器有效,新生代採用Parallel Scavenge GC時無效,大於這個值的對象直接在老年代進行分配

 

7、參數設置在哪裡?

      一般來說,一個服務器可能有多個java服務進行,對吧?是很多服務器都會有這種情況,那麼問題來了,那我要是統一在jvm配置文件修改jvm參數,那麼豈不是所有服務都是這個參數?所以有沒有其他辦法?

      有!!!!那就是在java進程啟動命令設置。

nohup java ${JAVA_OPT} -jar xxx.jar 2>&1&

JAVA_OPT的參數:裏面參數自行看要設置什麼,以及具體的參數值

JAVA_OPT=”-server -Xms256m -Xmx256m -Xmn512m -XX:MetaspaceSize=64m -XX:MaxMatespaceSize=256m”