線上linux系統故障排查之二:內存占用過高

《線上linux系統故障排查之一:CPU使用率過高》
《線上linux系統故障排查之二:內存占用過高》

前一篇文章介紹了《線上linux系統故障排查之一:CPU使用率過高》的解決方案,這篇主要分析系統內存占用過高的排查方法。
在Java開發中,對經常看到這兩種異常:

  • java.lang.OutOfMemoryError: PermGen space
  • java.lang.OutOfMemoryError: Java heap space

一、異常出現的原因

1.Java.lang.OutOfMemoryError: PermGen space

PermGen space全稱是Permanent Generation space,是指內存的永久保存區域, 這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGen space中, 它和存放類實例(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程序運行期對 PermGen space進行清理,所以如果你的應用中有很多CLASS的話,就很可能出現PermGen space錯誤。如果你的WEB或者APP用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那么就會產生此錯誤信息。

解決方法:
1.調整PermSize、MaxPermSize的大小;
2.減少jar重復使用,重復占用內存。

2.java.lang.OutOfMemoryError: Java heap space

Heap size 設置 JVM堆的設置是指java程序運行過程中JVM可以調配使用的內存空間的設置.JVM在啟動的時候會自動設置Heap size的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)是物理內存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。

在JVM中,如果98%的時間是用于GC且可用的Heap size 不足2%的時候將拋出此異常信息。提示:Heap Size 最大不要超過可用物理內存的80%,一般的要將-Xms和-Xmx選項設置為相同,而-Xmn為1/4的-Xmx值。

二、異常原因排查步驟

1.通過jstat命令查詢gc情況

通過top命令定位到內存占用過高的進程PID后,排查該進程的GC情況,

命令:jstat -gccause 41843 2000

  • 每間隔2s查詢進程pid = 41843 的gc情況;
  • gccause表示輸出-gcutil提供的信息以及最后一次執行GC的發生原因和當前所執行的GC的發生原因。
jstat命令的結果
2.通過jmap命令查詢進程實體類內存占用情況

如果步驟1中發現,gc非常頻繁,則可以使用jmap命令查詢進程實體類內存占用情況。

命令: jmap -histo:live 41843 | head -n 100

  • 查詢進程pid = 41843 存活的對象占用內存前100排序。
jmap 命令結果

如上圖可以看出,jdbc所占用的存活對象特別多,而且占用的內存也很高,從這里就可以看出,需要去檢查下mysql的調用中,哪里存在問題,有內存泄露。

3.通過jmap命令查詢進程堆的使用情況

如果以上沒有查出問題,可以看看進程中,新生代、老年代、永久代的使用情況。

命令: jmap -heap 41843

jmap -heap 41843結果

如上圖,如果發現頻繁的gc是因為新生代、老年代、永久代分配的大小有問題,則可以通過修改設置解決。

永久代解決方法(同上):
1.調整PermSize、MaxPermSize的大小;
2.減少jar重復使用,重復占用內存。

新生代、老年代解決方法:
1.調整Xms -Xmx -Xmn的大小

示例及參數注解:

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:PermSize=64M -XX:MaxPermSize=128M -XX:MaxTenuringThreshold=0

-Xmx3550m:設置JVM最大可用內存為3550M。
-Xms3550m:設置JVM促使內存為3550m。此值可以設置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內存;
-Xmn2g:設置年輕代大小為2G。整個JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8;
-Xss128k:設置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右;
-XX:NewRatio=4:設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置為4,則年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5;
-XX:SurvivorRatio=4:設置年輕代中Eden區與Survivor區的大小比值。設置為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6;
-XX:PermSize=64M JVM初始分配的非堆內存(永久代);
-XX:MaxPermSize=128M JVM最大允許分配的非堆內存,按需分配;
-XX:MaxTenuringThreshold=0:設置垃圾最大年齡。如果設置為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對于年老代比較多的應用,可以提高效率。如果將此值設置為一個較大值,則年輕代對象會在Survivor區進行多次復制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容