您的位置:首页 > 其它

性能分析4~jmap命令分析:堆信息、内存溢出

2017-08-25 16:45 441 查看
先看一个例子:jmap -heap pid该命令用于:展示pid的整体堆信息,运行结果如下

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,很有可能存在内存泄露情况,这时候就要借助JavaDump查看对象的情况。

2.
要制作堆Dump可以直接使用jvm自带的jmap命令

3.
可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。

4.
使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。

5.
也可以使用 jmap -dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容

6.
在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  性能分析