背景
在java应用开发中 我们难免会遇到java stack和heap的分析,在此记录一下对于发生OOM时候,该怎么进行分析
分析
- 首先我们得会几个工具,
jps jmap -heap jmap -histo:live jmap -dump:format=b,file=dump.hprof mat(Memory Analyzer Tool)
jps 用来看运行的应用是哪个pid
jmap -heap 用来查看该应用堆内存总体分布情况
jmap -histo:live 用来查看
jmap -dump 用来dump 应用整个堆的明细情况,便于具体分析oom的对象
mat 用来分析dump出来的文件的可视化软件,下载网址,根据自己的系统进行安装对应的软件就行
举个例子
$ jps 8727 DemoApplication 7914 Jps $ jmap -heap 8727 Debugger attached successfully. Server compiler detected. JVM version is 25.151-b12 using parallel threads in the new generation. using thread-local object allocation. Concurrent Mark-Sweep GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 1073741824 (1024.0MB) NewSize = 1073676288 (1023.9375MB) MaxNewSize = 1073676288 (1023.9375MB) OldSize = 65536 (0.0625MB) NewRatio = 2 SurvivorRatio = 1 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: New Generation (Eden + 1 Survivor Space): capacity = 715784192 (682.625MB) used = 463683480 (442.2030258178711MB) free = 252100712 (240.4219741821289MB) 64.7797877045041% used Eden Space: capacity = 357892096 (341.3125MB) used = 357892096 (341.3125MB) free = 0 (0.0MB) 100.0% used From Space: capacity = 357892096 (341.3125MB) used = 105791384 (100.8905258178711MB) free = 252100712 (240.4219741821289MB) 29.559575409008193% used To Space: capacity = 357892096 (341.3125MB) used = 0 (0.0MB) free = 357892096 (341.3125MB) 0.0% used concurrent mark-sweep generation: capacity = 65536 (0.0625MB) used = 65536 (0.0625MB) free = 0 (0.0MB) 100.0% used
这里我们能看到jvm队的各个分区的内存大小以及使用情况,以及堆的配置情况
为了分析导致OOM的对象,执行
$jmap -histo:live 8727 num #instances #bytes class name ---------------------------------------------- 1: 105666 12543792 [C 2: 5671 2608472 [B 3: 104224 2501376 java.lang.String 4: 17232 1902336 java.lang.Class 5: 55156 1764992 java.util.concurrent.ConcurrentHashMap$Node 6: 19700 1733600 java.lang.reflect.Method 7: 20805 1210960 [Ljava.lang.Object; 8: 27 885168 [Ljava.util.concurrent.ForkJoinTask; 9: 19971 798840 java.util.LinkedHashMap$Entry 10: 9524 710520 [Ljava.util.HashMap$Node; 11: 20654 660928 java.util.HashMap$Node 12: 10754 602224 java.util.LinkedHashMap 13: 319 530688 [Ljava.util.concurrent.ConcurrentHashMap$Node; 14: 27608 441728 java.lang.Object 15: 6672 351288 [I 16: 13947 307648 [Ljava.lang.Class; 17: 10444 250656 java.util.ArrayList 18: 3884 217504 java.lang.invoke.MemberName 19: 4444 175624 [Ljava.lang.String; 20: 4328 173120 java.lang.ref.SoftReference 21: 3317 159216 java.util.HashMap 22: 105 137344 [J 23: 5262 126288 org.springframework.core.MethodClassKey 24: 1447 115760 java.lang.reflect.Constructor 25: 3580 114560 java.util.LinkedList 26: 1491 107352 org.springframework.core.annotation.AnnotationAttributes 27: 1079 103584 org.springframework.beans.GenericTypeAwarePropertyDescriptor 28: 2540 101600 java.lang.invoke.MethodType 29: 3154 100928 java.lang.ref.WeakReference 30: 2437 97480 java.util.TreeMap$Entry 31: 3018 96576 java.lang.invoke.DirectMethodHandle 32: 1450 92800 java.net.URL 33: 3791 90984 sun.reflect.generics.tree.SimpleClassTypeSignature 34: 2546 81472 java.lang.invoke.MethodType$ConcurrentWeakInternSet$WeakEntry 35: 3175 76200 java.util.LinkedList$Node 36: 3791 72048 [Lsun.reflect.generics.tree.TypeArgument; 37: 2951 70824 java.beans.MethodRef
其中,
num 代表占用字节的大小排名
instances 代表实例的数目
bytes 代表占用的字节数
class name的具体含义如下:
B代表byte
C代表char
D代表double
F代表float
I代表int
1J代表long
Z代表boolean
前边有[代表数组,[I 就相当于int[]
这里其实就能看出个到底是哪个对象占用了太多导致了OOM
为了进一步分析,我们得dump出具体的堆明细
jmap -dump:live,format=b,file=dump.hprof
拿到dump.hprof文件,我们假设你已经安装了mat(如安装出现问题见下方注意),
按照 文件-》open heap Dump,倒入文件
选择Leak Suspects Report
选择Overview下的Histogram可以看到每个类的实例的数量大小,默认按照数量大小从大到小排列
选择你认为有可能OOM的对象,右击,选择List objects -》 with incoming references,则可以看到对应的代码的调用情况
注意:
如果在运行mat的过程中出现
java.lang.IllegalStateException: The platform metadata area could not be written: /private/var/folders/1l/mwvs7rf563x72kqcv7l6rb840000gn/T/AppTranslocation/F5D8FB45-D694-4157-BDAF-1D58A9B350BC/d/mat.app/Contents/MacOS/workspace/.metadata. By default the platform writes its content under the current working directory when the platform is launched. Use the -data parameter to specify a different content area for the platform.
即可解决