jmap(JVM Memory Map):作用一方面是获取dump文件(堆转储快照文件,二进制文件),它还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。开发人员可以在控制台中输入命令“jmap -help”查阅jmap工具的具体使用方式和一些标准选项配置。
他的不同的功能都是通过-option这个参数的不同来区分指定的。
官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jmap.html
基本使用语法为:
● jmap [option] pid
● jmap [option] executable core
● jmap [option] [server_id@] remote server IP or hostname
导出的dump文件可以显示当前的jvm空间的对象分布情况,可以帮助我们分析这类关于对象文件的一个情况。
说明:这些参数和linux下输入显示的命令多少会有不同,包括也受jdk版本的影响。
导出dump文件是jmap最重要的作用之一,Heap Dump称之为堆存储文件,指的是一个java进程在某个时间点的内存对象的快照,那一瞬间的捕捉。Heap Dump在触发内存快照的时候会保存的此刻的信息如下。
1、全部的对象
2、全部的类信息
3、gc roots的信息
4、线程栈和本地变量的数据
以上四种数据会被那一瞬间捕捉到。
说明一下:、
1、通常在写Heap Dump文件前会触发一个full GC,所以heap dump里面保存的都是full gc后留下的对象的信息。
2、由于生产dump文件比较耗时,因此需要耐心等待,尤其是大内存的时候镜像生成dump文件需要耗费更长的时间完成。
语法
> jmap -dump:format=b,file=<filename.hprof> <pid>
> jmap -dump:live,format=b,file=<filename.hprof> <pid>
开一个程序
/**
* @author: levi
* @description: -Xms60m -Xmx60m -XX:SurvivorRatio=8 堆空间初始和最大值设置为60m,s区和eden区的比例为8:1:1
* @date: 2022-10-3 20:10
* @version: 1.0
*/
public class GCtest {
// 100KB大小
static final int _100KB = 1024 * 100;
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
// 每120毫秒就添加100KB进这个集合里面
byte[] arr = new byte[_100KB];
list.add(arr);
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
查看jps找到线程id为136888
我们使用jmap来操作生成一下dump文件。
# 我们连续导出两个dump文件
jmap -dump:format=b,file=D:1.hprof 136888
Dumping heap to D:\1.hprof ...
Heap dump file created
jmap -dump:format=b,file=D:2.hprof 136888
Dumping heap to D:\2.hprof ...
Heap dump file created
# 然后使用live标签导出一个名字为3的dump文件
jmap -dump:live,format=b,file=D:3.hprof 136888
Dumping heap to D:\3.hprof ...
Heap dump file created
我们来解释一下这个命令
jmap -dump:format=b,file=D:1.hprof 136888
-dump表示就是导出堆文件的参数。
format=b.file表示我们导出这个文件的格式是标准格式,后面能用那些工具打开。
file=D:1.hprof 表示导出位置在D盘下面,名字为1,格式是hprof。
136888就是这个程序的进程id。
jmap -dump:live,format=b,file=D:3.hprof 136888
其余的一样,就是加了一个live标签,表示我们导出的是当前快照里面只有存活对象,回收的不导出了。上面那种是整个堆都导出,包括回收的和存活的对象。
有时候我们生产使用的时候,一般有存活的就行了,因为已经回收的不影响了,有问题都是那些没法回收的对象导致的。这样只导出存活的文件大小还能小点。
此时你每次执行这个命令都能导出对应的文件了。
但是这个hprof文件是二进制的,你得用工具看。文本打开看的就是乱码。
由于jmap将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。也就是说,由jmap导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差。
举个例子,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么:live选项将无法探知到这些对象。
另外,如果某个线程长时间无法跑到安全点,jmap将一直等下去。与前面讲的jstat则不同,垃圾回收器会主动将jstat所需要的摘要数据保存至固定位置之中,而jstat只需直接读取即可。
自动导出的意思就是你不用管,只要你配置好参数,等到他堆溢出了,自己会按照你得配置生成指定的文件。
只需要我们配置两个东西
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=d:\\5.hprof
第一个就是配置堆内存溢出的时候自动导出,第二行就是配置自动导出时候的hprof文件的位置。
等到溢出了就会生成该文件。
配置参数为:
-Xms60m
-Xmx60m
-XX:SurvivorRatio=8
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=d:\\5.hprof
public class GCtest {
// 100KB大小
static final int _100KB = 1024 * 100;
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
// 每120毫秒就添加100KB进这个集合里面
byte[] arr = new byte[_100KB];
list.add(arr);
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我们先运行那段程序,然后jps查看出线程id为8960.
我们执行jmap -heap 8960 > d:1.txt
jmap -histo 8960 > d:2.txt
我们为了方便查看把结果导出到txt文件里面。
我们程序运行的jvm参数为:-Xms60m -Xmx60m -XX:SurvivorRatio=8
我们查看一下-heap的结果为:
Attaching to process ID 8836, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
using thread-local object allocation.
Parallel GC with 8 thread(s)
# 下面就是堆内存大小的显式,和我们在jvm参数中配置的是一样的。
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 62914560 (60.0MB)
NewSize = 20971520 (20.0MB)
MaxNewSize = 20971520 (20.0MB)
OldSize = 41943040 (40.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
# 下面是我导出那一瞬间的时候当前的jvm内存里面的占用情况
Heap Usage:
PS Young Generation
Eden Space:
capacity = 16777216 (16.0MB)
used = 6128432 (5.8445281982421875MB)
free = 10648784 (10.155471801757812MB)
36.52830123901367% used
From Space:
capacity = 2097152 (2.0MB)
used = 0 (0.0MB)
free = 2097152 (2.0MB)
0.0% used
To Space:
capacity = 2097152 (2.0MB)
used = 0 (0.0MB)
free = 2097152 (2.0MB)
0.0% used
PS Old Generation
capacity = 41943040 (40.0MB)
used = 31067936 (29.628692626953125MB)
free = 10875104 (10.371307373046875MB)
74.07173156738281% used
1734 interned Strings occupying 156752 bytes.
我们查看一下-histo的结果为:
下面我们看到的他是你当前导出那一瞬间的空间的占用情况,比如类名,对象实例的大小,按从大到小排列的,我们可以据此查看一下空间里面有哪些大对象。
num #instances #bytes class name
----------------------------------------------
1: 358 33413272 [B
2: 2518 329744 [C
3: 603 69048 java.lang.Class
4: 2373 56952 java.lang.String
5: 605 36296 [Ljava.lang.Object;
6: 791 31640 java.util.TreeMap$Entry
7: 115 25032 [I
8: 197 8056 [Ljava.lang.String;
9: 79 5688 java.lang.reflect.Field
10: 85 5440 java.net.URL
11: 152 4864 java.util.Hashtable$Entry
12: 137 4384 java.util.concurrent.ConcurrentHashMap$Node
13: 11 4136 java.lang.Thread
14: 256 4096 java.lang.Integer
15: 99 3960 java.lang.ref.SoftReference
16: 100 3200 java.util.HashMap$Node
17: 42 2352 sun.misc.URLClassPath$JarLoader
18: 19 1968 [Ljava.util.HashMap$Node;
19: 123 1968 java.lang.Object
20: 46 1840 java.util.LinkedHashMap$Entry
21: 38 1824 sun.util.locale.LocaleObjectCache$CacheEntry
22: 21 1680 [Ljava.util.WeakHashMap$Entry;
23: 18 1440 java.lang.reflect.Constructor
24: 5 1424 [Ljava.util.concurrent.ConcurrentHashMap$Node;
25: 16 1408 java.lang.reflect.Method
26: 8 1264 [Ljava.util.Hashtable$Entry;
27: 13 1248 java.util.jar.JarFile$JarFileEntry
28: 31 1240 java.lang.ref.Finalizer
29: 25 1200 java.util.HashMap
30: 21 1176 sun.nio.cs.UTF_8$Encoder
31: 18 1152 java.util.jar.JarFile
32: 46 1104 java.io.ExpiringCache$Entry
33: 2 1064 [Ljava.lang.invoke.MethodHandle;
34: 19 1064 java.lang.Class$ReflectionData
35: 1 1040 [Ljava.lang.Integer;
36: 1 1040 [[C
37: 26 1040 java.io.ObjectStreamField
38: 21 1008 java.util.WeakHashMap
39: 27 864 com.intellij.rt.debugger.agent.CaptureAgent$InstrumentPoint
40: 26 832 java.lang.ref.ReferenceQueue
41: 19 760 sun.util.locale.BaseLocale$Key
42: 29 696 java.util.ArrayList
43: 8 640 [S
44: 19 608 java.util.Locale
45: 19 608 sun.util.locale.BaseLocale
46: 15 600 java.security.AccessControlContext
47: 15 600 sun.nio.cs.UTF_8$Decoder
48: 27 584 [Ljava.lang.Class;
49: 18 576 java.util.zip.ZipCoder
50: 8 512 java.util.concurrent.ConcurrentHashMap
51: 20 480 java.util.jar.Attributes$Name
52: 8 456 [Ljava.lang.reflect.Field;
53: 19 456 java.util.Locale$LocaleKey
54: 28 448 java.lang.ref.ReferenceQueue$Lock
55: 18 432 java.util.ArrayDeque
56: 13 416 java.io.File
57: 1 384 java.lang.ref.Finalizer$FinalizerThread
58: 6 384 java.nio.DirectByteBuffer
59: 8 384 java.util.zip.Inflater
60: 1 376 java.lang.ref.Reference$ReferenceHandler
61: 6 336 java.nio.DirectLongBufferU
62: 10 320 java.lang.OutOfMemoryError
63: 10 288 [Ljava.io.ObjectStreamField;
64: 12 288 sun.misc.MetaIndex
65: 6 240 java.util.WeakHashMap$Entry
66: 9 216 [Ljava.lang.reflect.Constructor;
67: 9 216 sun.reflect.NativeConstructorAccessorImpl
68: 4 192 java.util.Hashtable
69: 4 192 java.util.Properties
70: 4 192 java.util.TreeMap
71: 6 192 java.util.Vector
72: 8 192 java.util.zip.ZStreamRef
73: 3 168 java.lang.Package
74: 4 160 java.security.ProtectionDomain
75: 6 144 java.util.LinkedList$Node
76: 2 144 java.util.regex.Pattern
77: 6 144 sun.misc.PerfCounter
78: 9 144 sun.reflect.DelegatingConstructorAccessorImpl
79: 6 144 sun.security.util.DisabledAlgorithmConstraints$Constraint$Operator
80: 2 128 java.io.ExpiringCache$1
81: 4 128 java.security.CodeSource
82: 4 128 java.util.LinkedList
83: 3 120 java.io.FileDescriptor
84: 2 96 [Ljava.lang.reflect.Method;
85: 4 96 java.lang.RuntimePermission
86: 2 96 java.lang.ThreadGroup
87: 3 96 java.lang.ThreadLocal$ThreadLocalMap$Entry
88: 2 96 java.nio.HeapByteBuffer
89: 3 96 java.nio.file.attribute.FileTime
90: 3 96 java.util.Stack
91: 1 96 sun.misc.Launcher$AppClassLoader
92: 2 96 sun.misc.URLClassPath
93: 2 96 sun.nio.cs.StreamEncoder
94: 1 88 sun.misc.Launcher$ExtClassLoader
95: 1 80 [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;
96: 2 80 java.io.BufferedWriter
97: 2 80 java.io.ExpiringCache
98: 2 80 java.lang.ClassLoader$NativeLibrary
99: 5 80 java.lang.ThreadLocal
100: 2 80 sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint
101: 3 72 java.util.Collections$SynchronizedSet
102: 3 72 java.util.concurrent.atomic.AtomicLong
103: 2 64 [Ljava.lang.Thread;
104: 4 64 [Ljava.security.Principal;
105: 2 64 java.io.FileOutputStream
106: 2 64 java.io.FilePermission
107: 2 64 java.io.PrintStream
108: 2 64 java.lang.ClassValue$Entry
109: 2 64 java.lang.VirtualMachineError
110: 2 64 java.lang.ref.ReferenceQueue$Null
111: 2 64 java.security.BasicPermissionCollection
112: 2 64 java.security.Permissions
113: 4 64 java.security.ProtectionDomain$Key
114: 1 56 sun.nio.cs.ext.DoubleByte$Decoder
115: 1 48 [J
116: 1 48 [Ljava.util.concurrent.TimeUnit;
117: 2 48 java.io.BufferedOutputStream
118: 2 48 java.io.File$PathStatus
119: 2 48 java.io.FilePermissionCollection
120: 2 48 java.io.OutputStreamWriter
121: 2 48 java.nio.charset.CoderResult
122: 3 48 java.nio.charset.CodingErrorAction
123: 2 48 java.util.regex.Pattern$SliceI
124: 2 48 java.util.regex.Pattern$Start
125: 2 48 sun.instrument.TransformerManager
126: 2 48 sun.misc.NativeSignalHandler
127: 2 48 sun.misc.Signal
128: 2 48 sun.security.util.DisabledAlgorithmConstraints$DisabledConstraint
129: 2 40 [Lsun.instrument.TransformerManager$TransformerInfo;
130: 1 40 [Lsun.security.util.DisabledAlgorithmConstraints$Constraint$Operator;
131: 1 40 java.io.BufferedInputStream
132: 1 40 sun.nio.cs.StandardCharsets$Aliases
133: 1 40 sun.nio.cs.StandardCharsets$Cache
134: 1 40 sun.nio.cs.StandardCharsets$Classes
135: 1 40 sun.nio.cs.ext.ExtendedCharsets
136: 1 32 [Ljava.lang.OutOfMemoryError;
137: 2 32 [Ljava.lang.StackTraceElement;
138: 1 32 [Ljava.lang.ThreadGroup;
139: 2 32 com.intellij.rt.debugger.agent.CaptureAgent$ParamKeyProvider
140: 1 32 java.io.FileInputStream
141: 1 32 java.io.WinNTFileSystem
142: 1 32 java.lang.ArithmeticException
143: 2 32 java.lang.Boolean
144: 1 32 java.lang.NullPointerException
145: 1 32 java.lang.StringCoding$StringDecoder
146: 1 32 java.lang.StringCoding$StringEncoder
147: 2 32 java.nio.ByteOrder
148: 2 32 java.util.HashSet
149: 2 32 java.util.concurrent.atomic.AtomicInteger
150: 1 32 java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl
151: 1 32 java.util.regex.Pattern$Branch
152: 1 32 sun.instrument.InstrumentationImpl
153: 2 32 sun.net.www.protocol.jar.Handler
154: 1 32 sun.nio.cs.StandardCharsets
155: 1 24 [Ljava.io.File$PathStatus;
156: 1 24 [Ljava.lang.ClassValue$Entry;
157: 1 24 [Ljava.util.regex.Pattern$Node;
158: 1 24 [Lsun.launcher.LauncherHelper;
159: 1 24 com.intellij.rt.debugger.agent.CaptureAgent$FieldKeyProvider
160: 1 24 java.lang.ClassValue$Version
161: 1 24 java.lang.StringBuilder
162: 1 24 java.lang.ThreadLocal$ThreadLocalMap
163: 1 24 java.lang.invoke.MethodHandleImpl$4
164: 1 24 java.lang.reflect.ReflectPermission
165: 1 24 java.util.BitSet
166: 1 24 java.util.Collections$EmptyMap
167: 1 24 java.util.Collections$SetFromMap
168: 1 24 java.util.Collections$UnmodifiableRandomAccessList
169: 1 24 java.util.Locale$Cache
170: 1 24 java.util.concurrent.TimeUnit$1
171: 1 24 java.util.concurrent.TimeUnit$2
172: 1 24 java.util.concurrent.TimeUnit$3
173: 1 24 java.util.concurrent.TimeUnit$4
174: 1 24 java.util.concurrent.TimeUnit$5
175: 1 24 java.util.concurrent.TimeUnit$6
176: 1 24 java.util.concurrent.TimeUnit$7
177: 1 24 java.util.jar.Manifest
178: 1 24 java.util.regex.Pattern$Single
179: 1 24 sun.instrument.TransformerManager$TransformerInfo
180: 1 24 sun.launcher.LauncherHelper
181: 1 24 sun.misc.JarIndex
182: 1 24 sun.misc.URLClassPath$FileLoader
183: 1 24 sun.nio.cs.ISO_8859_1
184: 1 24 sun.nio.cs.ThreadLocalCoders$1
185: 1 24 sun.nio.cs.ThreadLocalCoders$2
186: 1 24 sun.nio.cs.US_ASCII
187: 1 24 sun.nio.cs.UTF_16
188: 1 24 sun.nio.cs.UTF_16BE
189: 1 24 sun.nio.cs.UTF_16LE
190: 1 24 sun.nio.cs.UTF_8
191: 1 24 sun.nio.cs.ext.GBK
192: 1 24 sun.reflect.NativeMethodAccessorImpl
193: 1 24 sun.security.util.DisabledAlgorithmConstraints
194: 1 24 sun.util.locale.BaseLocale$Cache
195: 1 16 [Ljava.lang.Throwable;
196: 1 16 [Ljava.security.cert.Certificate;
197: 1 16 com.intellij.rt.debugger.agent.CaptureAgent$1
198: 1 16 com.intellij.rt.debugger.agent.CaptureAgent$CaptureTransformer
199: 1 16 com.intellij.rt.debugger.agent.CaptureStorage$1
200: 1 16 java.io.FileDescriptor$1
201: 1 16 java.lang.CharacterDataLatin1
202: 1 16 java.lang.ClassValue$Identity
203: 1 16 java.lang.Runtime
204: 1 16 java.lang.String$CaseInsensitiveComparator
205: 1 16 java.lang.System$2
206: 1 16 java.lang.Terminator$1
207: 1 16 java.lang.invoke.MemberName$Factory
208: 1 16 java.lang.invoke.MethodHandleImpl$2
209: 1 16 java.lang.invoke.MethodHandleImpl$3
210: 1 16 java.lang.ref.Reference$1
211: 1 16 java.lang.ref.Reference$Lock
212: 1 16 java.lang.reflect.ReflectAccess
213: 1 16 java.net.URLClassLoader$7
214: 1 16 java.nio.Bits$1
215: 1 16 java.nio.charset.CoderResult$1
216: 1 16 java.nio.charset.CoderResult$2
217: 1 16 java.security.ProtectionDomain$2
218: 1 16 java.security.ProtectionDomain$JavaSecurityAccessImpl
219: 1 16 java.util.Collections$EmptyList
220: 1 16 java.util.Collections$EmptySet
221: 1 16 java.util.Hashtable$EntrySet
222: 1 16 java.util.WeakHashMap$KeySet
223: 1 16 java.util.concurrent.atomic.AtomicBoolean
224: 1 16 java.util.jar.Attributes
225: 1 16 java.util.jar.JavaUtilJarAccessImpl
226: 1 16 java.util.regex.Pattern$4
227: 1 16 java.util.regex.Pattern$BranchConn
228: 1 16 java.util.regex.Pattern$LastNode
229: 1 16 java.util.regex.Pattern$Node
230: 1 16 java.util.zip.ZipFile$1
231: 1 16 sun.misc.ASCIICaseInsensitiveComparator
232: 1 16 sun.misc.Launcher
233: 1 16 sun.misc.Launcher$Factory
234: 1 16 sun.misc.Perf
235: 1 16 sun.misc.Unsafe
236: 1 16 sun.net.www.protocol.file.Handler
237: 1 16 sun.reflect.DelegatingMethodAccessorImpl
238: 1 16 sun.reflect.ReflectionFactory
239: 1 16 sun.security.util.AlgorithmDecomposer
240: 1 16 sun.security.util.DisabledAlgorithmConstraints$Constraints
Total 9747 34058552
但是我们上面说的jmap都是基于那一瞬间的值,不是连续的。这就是一个弊端。
jamp -permstat pid查看系统的ClassLoader的信息
jmap -finalizerinfo 查看堆积在finalizer队列中的对象。
这两个在win下面不能运行。需要在linux系统运行。