JVM從入門到精通(九):JVM調優實戰 - arthas 的使用

Arthas 文檔

https://github.com/alibaba/arthas/blob/master/README_CN.md

在這裏插入圖片描述
運行起來我們的java程序

在這裏插入圖片描述
啓動 arthas 的 jar 文件,我們看到 剛纔運行的java程序的進程號是 1,所以敲進進程號 1 ,回車,它會把自己掛到這個進程上
在這裏插入圖片描述
之後就可以用 arthas 提供的一些命令,來觀察你的程序了
使用 help 查看 arthas 常用命令:
一些常用命令,包括:jvmdashboardheapdump等等
在這裏插入圖片描述
有了arthas,你就可以放棄大多數JDK自帶的命令了~

例如,導出堆文件,它有默認路徑,你也可以自己指定路徑。會對線上系統產生一些影響。所以我們能不導堆就不導堆,能在線定位就在線定位。
在這裏插入圖片描述
然後我們來分析這個導出的堆文件

在這裏插入圖片描述
導出之後,它會提醒你可以通過7000端口訪問
在這裏插入圖片描述
裏面有個 package 和 other 拉到最底下去找instance點進去,它就相當於jmap那個界面,能夠分析出哪個類包含的對象最多
在這裏插入圖片描述裏面還有一個強大的功能叫做:OQL,可以類似SQL的語言,查詢有哪些對象。語法還是很靈活的,也可以用where過濾
例如,select s from java.lang.String s

arthas還有一個更牛的地方叫做 redefine 熱替換
在這裏插入圖片描述
在這裏插入圖片描述

OOM 問題排查案例彙總

OOM產生的原因多種多樣,有些程序未必產生OOM,不斷FGC(CPU飆高,但內存回收特別少) (上面案例)

  1. 硬件升級系統反而卡頓的問題(見上)

  2. 線程池不當運用產生OOM問題(見上)
    不斷的往List里加對象(實在太LOW)

  3. jira問題
    實際系統不斷重啓
    解決問題 加內存 + 更換垃圾回收器 G1
    真正問題在哪兒?不知道

  4. tomcat http-header-size過大問題(Hector)

  5. lambda表達式導致方法區溢出問題(MethodArea / Perm Metaspace)
    LambdaGC.java -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails

   "C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\lib\idea_rt.jar=49316:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\work\ijprojects\JVM\out\production\JVM;C:\work\ijprojects\ObjectSize\out\artifacts\ObjectSize_jar\ObjectSize.jar" com.mashibing.jvm.gc.LambdaGC
   [GC (Metadata GC Threshold) [PSYoungGen: 11341K->1880K(38400K)] 11341K->1888K(125952K), 0.0022190 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
   [Full GC (Metadata GC Threshold) [PSYoungGen: 1880K->0K(38400K)] [ParOldGen: 8K->1777K(35328K)] 1888K->1777K(73728K), [Metaspace: 8164K->8164K(1056768K)], 0.0100681 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
   [GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] 1777K->1777K(73728K), 0.0005698 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
   [Full GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] [ParOldGen: 1777K->1629K(67584K)] 1777K->1629K(105984K), [Metaspace: 8164K->8156K(1056768K)], 0.0124299 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 
   java.lang.reflect.InvocationTargetException
   	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   	at java.lang.reflect.Method.invoke(Method.java:498)
   	at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:388)
   	at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:411)
   Caused by: java.lang.OutOfMemoryError: Compressed class space
   	at sun.misc.Unsafe.defineClass(Native Method)
   	at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:63)
   	at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399)
   	at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
   	at java.security.AccessController.doPrivileged(Native Method)
   	at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
   	at sun.reflect.MethodAccessorGenerator.generateSerializationConstructor(MethodAccessorGenerator.java:112)
   	at sun.reflect.ReflectionFactory.generateConstructor(ReflectionFactory.java:398)
   	at sun.reflect.ReflectionFactory.newConstructorForSerialization(ReflectionFactory.java:360)
   	at java.io.ObjectStreamClass.getSerializableConstructor(ObjectStreamClass.java:1574)
   	at java.io.ObjectStreamClass.access$1500(ObjectStreamClass.java:79)
   	at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:519)
   	at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:494)
   	at java.security.AccessController.doPrivileged(Native Method)
   	at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:494)
   	at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:391)
   	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1134)
   	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
   	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
   	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
   	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
   	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
   	at javax.management.remote.rmi.RMIConnectorServer.encodeJRMPStub(RMIConnectorServer.java:727)
   	at javax.management.remote.rmi.RMIConnectorServer.encodeStub(RMIConnectorServer.java:719)
   	at javax.management.remote.rmi.RMIConnectorServer.encodeStubInAddress(RMIConnectorServer.java:690)
   	at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:439)
   	at sun.management.jmxremote.ConnectorBootstrap.startLocalConnectorServer(ConnectorBootstrap.java:550)
   	at sun.management.Agent.startLocalManagementAgent(Agent.java:137)
  1. 直接內存溢出問題(少見)
    《深入理解Java虛擬機》P59,使用Unsafe分配直接內存,或者使用NIO的問題

  2. 棧溢出問題
    -Xss設定太小

  3. 比較一下這兩段程序的異同,分析哪一個是更優的寫法:

    Object o = null;
    for(int i=0; i<100; i++) {
        o = new Object();
        //業務處理
        //這種寫法更好,每一次進入循環,都是隻有一個引用指向它,其他的沒有指向的引用,就有可能被回收啦
    }
    
    for(int i=0; i<100; i++) {
        Object o = new Object();
        // 循環結束才釋放,纔會被回收
    }
    
  4. 重寫finalize引發頻繁GC
    小米雲,HBase同步系統,系統通過nginx訪問超時報警(系統CPU在頻繁GC,CPU飈高),最後排查,C++程序員重寫finalize引發頻繁GC問題
    爲什麼C++程序員會重寫finalize?(new對象需要手動回收內存,調用析構函數delete,以爲finalize就是析構函數,所以就把它重寫了)
    finalize耗時比較長,裏面寫了一些複雜的邏輯,耗時(200ms),回收不過來了

  5. 如果有一個系統,堆內存一直消耗不超過10%,但是觀察GC日誌,發現FGC總是頻繁產生,會是什麼引起的?
    因爲有人顯式調用了System.gc() (這個比較Low)

  6. Distuptor有個可以設置鏈的長度,如果過大,然後對象大,消費完不主動釋放,會溢出

  7. 用jvm都會溢出,mycat用崩過,1.6.5某個臨時版本解析sql子查詢算法有問題,9個exists的聯合sql就導致生成幾百萬的對象

  8. new 大量線程,會產生 native thread OOM,(low)應該用線程池,
    解決方案:減少堆空間(太TMlow了),預留更多內存產生native thread
    JVM內存佔物理內存比例 50% - 80%

希望大家看完這節課內容並且實操之後,就可以“有過JVM調優經驗”了~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章