【JVM命令及問題排查】

java中的gc log解讀

eclipse的優化 gc.log

一次讓人難以忘懷的排查頻繁Full GC過程

一個GC頻繁的Case

堆內存佔用很小 但是 JVM 頻繁full gc 問題排查

JVM中GC時,堆內存是如何動態變化的(JDK1.7)

 

使用jmap和MAT分析JVM堆內存

Jmap+MAT 排查內存泄漏

 

關於內存溢出

 

 

 

Young(Nursery):年輕代

Old(Tenured):年老代

Permanent(Perm):持久代

        裝載Class信息等基礎數據

 

堆設置 

-Xms:初始堆大小 ,默認是物理內存的1/64

-Xmx:最大堆大小 

-Xmn:年輕代大小

-Xss:jvm啓動的每個線程分配的內存大小

-XX:NewSize=n:設置年輕代大小 

-XX:PermSize=64m設置持久代大小

-XX:MaxPermSize=n:設置持久代最大大小

          MaxPermSize過小會導致:java.lang.OutOfMemoryError: PermGen space

 

-XX:NewRatio=n:設置年輕代和年老代的比值。如:爲3,表示年輕代與年老代比值爲1:3,年輕代佔整個年輕代年老代和的1/4 

-XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區佔整個年輕代的1/5 

-XX:MaxTenuringThreshold 

          如果設置爲0的話,則年輕代對象不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設置爲一個較大值,則年輕代對象會在Survivor區進行多次複製,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。

 

 

-Xmx512m: (max堆最大可用內存爲512M。

-Xms512m: (small)堆初始內存爲512m。

此值可以設置與-Xmx最大值相同,以避免每次垃圾回收完成後JVM動態調節Java堆大小而耗費延長其週期。 

 

-Xmn192m :(new)設置年輕代大小爲192m。

整個JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小爲64m,所以增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8。

 

 

垃圾回收統計信息 

-XX:+PrintGC 

-XX:+PrintGCDetails 

-XX:+PrintGCTimeStamps 

-Xloggc:filename

 

-XX:+PrintGC 

輸出形式:[GC 118250K->113543K(130112K), 0.0094143 secs] 

[Full GC 121376K->10414K(130112K), 0.0650971 secs]

 

-XX:+PrintGCDetails 

輸出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] 

[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

 

-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可與上面兩個混合使用 

輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]

 

默認java程序是不會開啓gc log

對於生產環境下的java程序可以加上來生成gc log,方便出現問題的時候去排查

-verbose:gc -Xloggc:/usr/gclog -XX:+PrintGCDetails XX:+PrintGCTimeStamps

 

收集器設置 

-XX:+UseSerialGC:設置串行收集器 

-XX:+UseParallelGC:設置並行收集器 

-XX:+UseParalledlOldGC:設置並行年老代收集器 

-XX:+UseConcMarkSweepGC:設置併發收集器

 

-XX:+DisableExplicitGC這個將會忽略手動調用GC的代碼使得 System.gc()的調用就會變成一個空調用,完全不會觸發任何GC。

 

 

======================================================================

java中的gc log解讀

https://my.oschina.net/hadooper/blog/418918

eclipse的優化 gc.log

https://blog.csdn.net/z69183787/article/details/39136119

 

默認java程序是不會開啓gc log

對於生產環境下的java程序可以加上來生成gc log,方便出現問題的時候去排查

-verbose:gc -Xloggc:/usr/gclog -XX:+PrintGCDetails XX:+PrintGCTimeStamps

 

 

Linux如何開啓tomcat的gc日誌並查看

進入到了tomcat的bin的目錄下中,命令中vi catalina.sh  來編輯

然後在該文件中cygwin=false上面

添加爲

JAVA_OPTS="-Xms128m -Xmx256m -Xmn100m -XX:MaxPermSize=30m -Xloggc:/usr/local/tomcat/logs/gc.$$.log"

gc開啓完成之後,只要啓動了tomcat之後,就可目錄下生成了gc的log的日誌內容。

 

場景一:

[GC [DefNew: 3298K->149K(5504K), 0.0053498 secs] 3298K->3221K(9600K), 0.0053750 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

看一下這行:

DefNew表示新生態:3298K->149K(5504K), 0.0053498 secs

表示新生態由3298K回收變成了149K,即之前的3M回收了,【5504K表示該區域的總內存大小】

3298K->3221K(9600K), 0.0053750 secs] 表示整個jvm堆的大小由於沒有可以回收的對象,所以總大小本質沒發生改變,9600K是java的總堆大小9600K。(雖然分配10M,其中還有持久態等其他內存區域)

 

[Times: user=0.00 sys=0.00, real=0.01 secs] 表示gc所花費的系統資源

 

 

場景二:

0.209: [GC 0.209: [DefNew: 4416K->511K(4928K), 0.0034707 secs] 4416K->614K(15872K), 0.0035239 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]  

6.383: [GC 6.383: [DefNew: 18880K->1985K(21184K), 0.0055311 secs] 46992K->30098K(68040K), 0.0055694 secs]

 

這6秒中GC日誌打了69次, 而內存回收率還是蠻高的 young區18880-1985=16895 jvm 46992-30098=16894 都快接近100%了,可以看出young區是由小到大在不斷調整大小,所以不斷GC,因此設一個初始值吧,據說設置heap的1/4比較好,那就是 128M,所以eclipse.ini加入 

-Xmn128m

 

場景三:

103.759: [Full GC (System) 103.759: [Tenured: 81882K->66784K(393216K), 0.3287387 secs] 185350K->66784K(511232K), [Perm : 53464K->53414K(65536K)], 0.3287897 secs] [Times: user=0.33 sys=0.00, real=0.33 secs]

仔細觀察日誌,發現Full GC (System) 字樣,這個意思是eclipse裏調用了System.gc()手動觸發了系統GC,在eclipse.ini里加入: 

-XX:+DisableExplicitGC

-XX:+DisableExplicitGC這個將會忽略手動調用GC的代碼使得 System.gc()的調用就會變成一個空調用,完全不會觸發任何GC。

 

======================================================================

 關於內存溢出

https://blog.csdn.net/bbaiggey/article/details/50885943

 

第一類內存溢出,也是大家認爲最多,第一反應認爲是的內存溢出,就是堆棧溢出:

那什麼樣的情況就是堆棧溢出呢?當你看到下面的關鍵字的時候它就是堆棧溢出了:

 

java.lang.OutOfMemoryError: ......java heap space.....

 

也就是當你看到heap相關的時候就肯定是堆棧溢出了,此時如果代碼沒有問題的情況下,適當調整-Xmx和-Xms是可以避免的,不過一定是代碼沒有問題的前提,爲什麼會溢出呢,要麼代碼有問題,要麼訪問量太多並且每個訪問的時間太長或者數據太多,導致數據釋放不掉,因爲垃圾回收器是要找到那些是垃圾才能回收,這裏它不會認爲這些東西是垃圾,自然不會去回收了;主意這個溢出之前,可能系統會提前先報錯關鍵字爲:

 

java.lang.OutOfMemoryError:GC over head limit exceeded

 

這種情況是當系統處於高頻的GC狀態,而且回收的效果依然不佳的情況,就會開始報這個錯誤,這種情況一般是產生了很多不可以被釋放的對象,有可能是引用使用不當導致,或申請大對象導致,但是java heap space的內存溢出有可能提前不會報這個錯誤,也就是可能內存就直接不夠導致,而不是高頻GC.

 

 

第二類內存溢出,PermGen的溢出,或者PermGen 滿了的提示,你會看到這樣的關鍵字:

關鍵信息爲:

java.lang.OutOfMemoryError: PermGen space

 

原因:系統的代碼非常多或引用的第三方包非常多、或代碼中使用了大量的常量、或通過intern注入常量、或者通過動態代碼加載等方法,導致常量池的膨脹,雖然JDK 1.5以後可以通過設置對永久帶進行回收,但是我們希望的是這個地方是不做GC的,它夠用就行,所以一般情況下今年少做類似的操作,所以在面對這種情況常用的手段是:增加-XX:PermSize和-XX:MaxPermSize的大小。

 

 

第三類內存溢出:在使用ByteBuffer中的allocateDirect()的時候會用到,很多javaNIO的框架中被封裝爲其他的方法

溢出關鍵字:

java.lang.OutOfMemoryError: Direct buffer memory

 

如果你在直接或間接使用了ByteBuffer中的allocateDirect方法的時候,而不做clear的時候就會出現類似的問題,常規的引用程序IO輸出存在一個內核態與用戶態的轉換過程,也就是對應直接內存與非直接內存,如果常規的應用程序你要將一個文件的內容輸出到客戶端需要通過OS的直接內存轉換拷貝到程序的非直接內存(也就是heap中),然後再輸出到直接內存由操作系統發送出去,而直接內存就是由OS和應用程序共同管理的,而非直接內存可以直接由應用程序自己控制的內存,jvm垃圾回收不會回收掉直接內存這部分的內存,所以要注意了哦。

如果經常有類似的操作,可以考慮設置參數:-XX:MaxDirectMemorySize

 

 

第四類內存溢出錯誤:

溢出關鍵字:

java.lang.StackOverflowError

 

這個參數直接說明一個內容,就是-Xss太小了,我們申請很多局部調用的棧針等內容是存放在用戶當前所持有的線程中的,線程在jdk 1.4以前默認是256K,1.5以後是1M,如果報這個錯,只能說明-Xss設置得太小,當然有些廠商的JVM不是這個參數,本文僅僅針對Hotspot VM而已;不過在有必要的情況下可以對系統做一些優化,使得-Xss的值是可用的。

發佈了701 篇原創文章 · 獲贊 67 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章