背景
在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: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.
找到对应mat下的Contents/Eclipse/MemoryAnalyzer.ini文件
增加
-data
## /Users/path/to/dir为可写权限的目录
/Users/path/to/dir
即可解决
网友评论