性能分析4~jmap命令分析:堆信息、内存溢出
2017-08-25 16:45
441 查看
先看一个例子:jmap -heap pid该命令用于:展示pid的整体堆信息,运行结果如下
这些参数有什么用呢,我们看如下几行:
我们可以看出:年轻代三个区域(eden、From Space、To Space)的大小、年老代的大小,以及已经使用、剩余的大小;
根据这些结果、再结合:
jstat -gcnew pid:查询new对象的信息
jstat -gcold pid:查询old对象的信息
这两条命令中的gc频率,我们可以得出设置的各个代的大小是否合理,若不合理,如何调整。调整的策略必须以实际应用为主,比如说:full gc的时间停顿让客户感觉明显,我们分析原因得知是old区域设置的过大,导致一次full gc需要的时间过久;如果我们直接缩小old区域的大小,又回发现full gc过于频繁;这个时候也许我们需要更换gc的算法........
我们现在开始看jmap的定义:
我们先只看几个简单的:
-heap:打印jvm heap的情况
-histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
-heap上面已经给出过例子了,下面我们用-histo来分析内存溢出;
首先写一个能导致内存溢出的程序:
运行后,执行如下命令:
发现产生了140000多个Apple实例,140000多个String对象,并且在不断的增加,这是肯定有问题的,至于怎么修改,由于我们写的程序没有太大的意义,就不做说明了,根据实际情况来修改,此处只是为了展示。
总结:给的例子并不好,想说的是,根据命令的输出结果去发现异常信息最重要。
分析问题流程:
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
4.使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap -dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。
zhengchao1991deMacBook-Pro:~ zhengchao1991$ jmap -heap 33628 Attaching to process ID 33628, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.79-b02 using thread-local object allocation. Parallel GC with 8 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 536870912 (512.0MB) NewSize = 1310720 (1.25MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 268435456 (256.0MB) G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 145227776 (138.5MB) used = 3721808 (3.5493927001953125MB) free = 141505968 (134.9506072998047MB) 2.5627384116933665% used From Space: capacity = 7864320 (7.5MB) used = 0 (0.0MB) free = 7864320 (7.5MB) 0.0% used To Space: capacity = 7864320 (7.5MB) used = 0 (0.0MB) free = 7864320 (7.5MB) 0.0% used PS Old Generation capacity = 157810688 (150.5MB) used = 111650416 (106.47813415527344MB) free = 46160272 (44.02186584472656MB) 70.74959080084614% used PS Perm Generation capacity = 129499136 (123.5MB) used = 129255872 (123.26800537109375MB) free = 243264 (0.23199462890625MB) 99.81215009805162% used 45138 interned Strings occupying 4690064 bytes.
这些参数有什么用呢,我们看如下几行:
PS Young Generation Eden Space:#Eden区内存分布 capacity = 87883776 (83.8125MB) used = 31053080 (29.614524841308594MB) free = 56830696 (54.197975158691406MB) 35.33425782706469% used From Space:#其中一个Survivor区的内存分布 capacity = 13828096 (13.1875MB) used = 196608 (0.1875MB) free = 13631488 (13.0MB) 1.4218009478672986% used To Space:#另一个Survivor区的内存分布 capacity = 16384000 (15.625MB) used = 0 (0.0MB) free = 16384000 (15.625MB) 0.0% used PS Old Generation#当前的Old区内存分布 capacity = 156172288 (148.9375MB) used = 27098208 (25.842864990234375MB) free = 129074080 (123.09463500976562MB) 17.35148299805917% used
我们可以看出:年轻代三个区域(eden、From Space、To Space)的大小、年老代的大小,以及已经使用、剩余的大小;
根据这些结果、再结合:
jstat -gcnew pid:查询new对象的信息
jstat -gcold pid:查询old对象的信息
这两条命令中的gc频率,我们可以得出设置的各个代的大小是否合理,若不合理,如何调整。调整的策略必须以实际应用为主,比如说:full gc的时间停顿让客户感觉明显,我们分析原因得知是old区域设置的过大,导致一次full gc需要的时间过久;如果我们直接缩小old区域的大小,又回发现full gc过于频繁;这个时候也许我们需要更换gc的算法........
我们现在开始看jmap的定义:
Usage: jmap [option] <pid> (to connect to running process) jmap [option] <executable <core> (to connect to a core file) jmap [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server) where <option> is one of: <none> to print same info as Solaris pmap -heap to print java heap summary -histo[:live] to print histogram of java object heap; if the "live" suboption is specified, only count live objects -permstat to print permanent generation statistics -finalizerinfo to print information on objects awaiting finalization -dump:<dump-options> to dump java heap in hprof binary format dump-options: live dump only live objects; if not specified, all objects in the heap are dumped. format=b binary format file=<file> dump heap to <file> Example: jmap -dump:live,format=b,file=heap.bin <pid> -F force. Use with -dump:<dump-options> <pid> or -histo to force a heap dump or histogram when <pid> does not respond. The "live" suboption is not supported in this mode. -h | -help to print this help message -J<flag> to pass <flag> directly to the runtime system
我们先只看几个简单的:
-heap:打印jvm heap的情况
-histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
-heap上面已经给出过例子了,下面我们用-histo来分析内存溢出;
首先写一个能导致内存溢出的程序:
package deadlock; import java.math.BigDecimal; public class Apple { public String name; public BigDecimal price; public Apple(String name, BigDecimal price) { this.name = name; this.price = price; System.out.println(name); } } package deadlock; import java.math.BigDecimal; public class TestJmap { public static void main(String[] args){ int i=0; while(true){ new Apple("apple"+i++,BigDecimal.ONE); } } }
运行后,执行如下命令:
zhengchao1991deMacBook-Pro:~ zhengchao1991$ jmap -histo 38876 num #instances #bytes class name ---------------------------------------------- 1: 293271 14077008 java.nio.HeapCharBuffer 2: 147692 5957408 [C 3: 147672 3544128 java.lang.String 4: 146636 3519264 deadlock.Apple 5: 116 2852184 [I 6: 6162 794048 <methodKlass> 7: 6162 718552 <constMethodKlass> 8: 403 488912 <constantPoolKlass> 9: 367 300000 <constantPoolCacheKlass> 10: 403 278312 <instanceKlassKlass> 11: 565 94464 [B 12: 466 45816 java.lang.Class 13: 688 45360 [[I 14: 613 38072 [S 15: 46 25024 <objArrayKlassKlass> 16: 73 24952 <meth我们看这几行:
num #instances #bytes class name ---------------------------------------------- 1: 293271 14077008 java.nio.HeapCharBuffer 2: 147692 5957408 [C 3: 147672 3544128 java.lang.String 4: 146636 3519264 deadlock.Apple
发现产生了140000多个Apple实例,140000多个String对象,并且在不断的增加,这是肯定有问题的,至于怎么修改,由于我们写的程序没有太大的意义,就不做说明了,根据实际情况来修改,此处只是为了展示。
总结:给的例子并不好,想说的是,根据命令的输出结果去发现异常信息最重要。
分析问题流程:
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
4.使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap -dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。
相关文章推荐
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- 命令:jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- tack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- 0132 jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
- jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令