Arthas 文檔
https://github.com/alibaba/arthas/blob/master/README_CN.md
運行起來我們的java程序
啓動 arthas 的 jar 文件,我們看到 剛纔運行的java程序的進程號是 1,所以敲進進程號 1 ,回車,它會把自己掛到這個進程上
之後就可以用 arthas 提供的一些命令,來觀察你的程序了
使用 help 查看 arthas 常用命令:
一些常用命令,包括:jvm
,dashboard
,heapdump
等等
有了arthas,你就可以放棄大多數JDK自帶的命令了~
例如,導出堆文件,它有默認路徑,你也可以自己指定路徑。會對線上系統產生一些影響。所以我們能不導堆就不導堆,能在線定位就在線定位。
然後我們來分析這個導出的堆文件
導出之後,它會提醒你可以通過7000端口訪問
裏面有個 package 和 other 拉到最底下去找instance點進去,它就相當於jmap那個界面,能夠分析出哪個類包含的對象最多
裏面還有一個強大的功能叫做:OQL,可以類似SQL的語言,查詢有哪些對象。語法還是很靈活的,也可以用where過濾
例如,select s from java.lang.String s
arthas還有一個更牛的地方叫做 redefine 熱替換
OOM 問題排查案例彙總
OOM產生的原因多種多樣,有些程序未必產生OOM,不斷FGC(CPU飆高,但內存回收特別少) (上面案例)
-
硬件升級系統反而卡頓的問題(見上)
-
線程池不當運用產生OOM問題(見上)
不斷的往List里加對象(實在太LOW) -
jira問題
實際系統不斷重啓
解決問題 加內存 + 更換垃圾回收器 G1
真正問題在哪兒?不知道 -
tomcat http-header-size過大問題(Hector)
-
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)
-
直接內存溢出問題(少見)
《深入理解Java虛擬機》P59,使用Unsafe分配直接內存,或者使用NIO的問題 -
棧溢出問題
-Xss設定太小 -
比較一下這兩段程序的異同,分析哪一個是更優的寫法:
Object o = null; for(int i=0; i<100; i++) { o = new Object(); //業務處理 //這種寫法更好,每一次進入循環,都是隻有一個引用指向它,其他的沒有指向的引用,就有可能被回收啦 }
for(int i=0; i<100; i++) { Object o = new Object(); // 循環結束才釋放,纔會被回收 }
-
重寫finalize引發頻繁GC
小米雲,HBase同步系統,系統通過nginx訪問超時報警(系統CPU在頻繁GC,CPU飈高),最後排查,C++程序員重寫finalize引發頻繁GC問題
爲什麼C++程序員會重寫finalize?(new對象需要手動回收內存,調用析構函數delete,以爲finalize就是析構函數,所以就把它重寫了)
finalize耗時比較長,裏面寫了一些複雜的邏輯,耗時(200ms),回收不過來了 -
如果有一個系統,堆內存一直消耗不超過10%,但是觀察GC日誌,發現FGC總是頻繁產生,會是什麼引起的?
因爲有人顯式調用了System.gc() (這個比較Low) -
Distuptor有個可以設置鏈的長度,如果過大,然後對象大,消費完不主動釋放,會溢出
-
用jvm都會溢出,mycat用崩過,1.6.5某個臨時版本解析sql子查詢算法有問題,9個exists的聯合sql就導致生成幾百萬的對象
-
new 大量線程,會產生 native thread OOM,(low)應該用線程池,
解決方案:減少堆空間(太TMlow了),預留更多內存產生native thread
JVM內存佔物理內存比例 50% - 80%
希望大家看完這節課內容並且實操之後,就可以“有過JVM調優經驗”了~