20210520 使用jmap分析虚拟机内存状况
Posted 陈如水
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20210520 使用jmap分析虚拟机内存状况相关的知识,希望对你有一定的参考价值。
堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的。
栈与堆
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。而堆则是所有线程共享的。栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。
什么是堆Dump
堆Dump是反应Java堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的状态等。 一般,在内存不足、GC异常等情况下,我们就会怀疑有内存泄露。这个时候我们就可以制作堆Dump来查看具体情况,分析原因。
outOfMemoryError 年老代内存不足。
outOfMemoryError:PermGen Space 永久代内存不足。
outOfMemoryError:GC overhead limit exceed 垃圾回收时间占用系统运行时间的98%或以上。
进行内存分析主要分析以下几点:
1.程序是否内存泄露;
2.程序中大对象的占用是否合理;
3.程序中部分对象产生内存是否可以优化;
jmap -heap:打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况。
jmap -histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
jmap -histo:live :同上,但是只打印存活对象的情况,显示堆中对象的统计信息。打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.live选项会在转储前强制触发一次full GC(以减小文件体积)
jmap -dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.dump 将内存使用的详细情况输出到文件
可以看出使用的是什么垃圾收集器?
Concurrent Mark-Sweep GC CMS gc 并发标记清除垃圾收集器。
jmap -heap pid 命令查询JVM Heap初始化参数配置。虚拟机初始化参数配置。
jmap -heap pid可以查看当前JVM Heap初始化参数配置.当前虚拟机的配置参数。
jmap -dump:live,format=b,file=dmp.hprof (pid) 打印这一时刻的内存快照 (打印所有对象,包含死去的)
jmap -histo:live 1117 | head -n 20 打印占用堆内存最多的实例数量
jmap -histo:live 1117 命令 其中最后一行(total行)分别记录了实例总数、程序占用总内存数,本例显示的程序总占用内存约295M 对象只占用了300M左右的内存,但是为什么内存使用率80%?
但是如果去掉live选项,会有1G的内存占用,为什么对象没有存活,但是也没有回收?
jmap -heap <pid> :使用的垃圾收集器,虚拟机的初始化配置参数
[work(chenrushui)@tjtx145-59-206 ~]$ jmap -heap 1049
Attaching to process ID 1049, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.231-b11
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 4294967296 (4096.0MB)
NewSize = 1610612736 (1536.0MB)
MaxNewSize = 1610612736 (1536.0MB)
OldSize = 1610612736 (1536.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 268435456 (256.0MB)
CompressedClassSpaceSize = 796917760 (760.0MB)
MaxMetaspaceSize = 805306368 (768.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 1449590784 (1382.4375MB)
used = 1170377376 (1116.1588439941406MB)
free = 279213408 (266.2786560058594MB)
80.73846694654483% used
Eden Space:
capacity = 1288568832 (1228.875MB)
used = 1167246768 (1113.1732635498047MB)
free = 121322064 (115.70173645019531MB)
90.58474324482187% used
From Space:
capacity = 161021952 (153.5625MB)
used = 3130608 (2.9855804443359375MB)
free = 157891344 (150.57691955566406MB)
1.944211929563492% used
To Space:
capacity = 161021952 (153.5625MB)
used = 0 (0.0MB)
free = 161021952 (153.5625MB)
0.0% used
concurrent mark-sweep generation:
capacity = 1610612736 (1536.0MB)
used = 305178048 (291.04046630859375MB)
free = 1305434688 (1244.9595336914062MB)
18.947947025299072% used
55575 interned Strings occupying 6233032 bytes.
查看堆内存空间的变化:
1)创建大对象之前,
2)创建大对象之后,
3)触发gc以后; Eden区域used的变化。
jmap -histo <pid>
instances(对象的实例个数)、bytes(总占用的字节数)、classs name(对应的就是 Class 文件里的 class 的标识 )。它基本是按照使用使用大小逆序排列的。
jmap -histo pid 输出的[B 占用很高,请问问题会在哪里?
[C对象占用Heap这么多,往往跟String有关,String其内部使用final char[]数组来保存数据的。
[work(chenrushui)@tjtx145-59-206 ~]$ jmap -histo 1049 | head -n 10
num #instances #bytes class name
----------------------------------------------
1: 4530762 383164064 [C
2: 220104 111601216 [B
3: 151132 67165712 [I
4: 2146366 51512784 java.lang.String
5: 584411 51428168 java.lang.reflect.Method
6: 487305 26470200 [Ljava.lang.Object;
7: 624597 19987104 java.util.HashMap$Node
Total 22888910 1426623680
jmap -dump:format=b,file=dum.hprof <pid> 打印当前时刻的内存快照
对象的大小有两种统计方式:
- 本身大小(Shallow Size):对象本来的大小。
- 保留大小(Retained Size): 当前对象大小 + 当前对象直接或间接引用到的对象的大小总和。
看本身大小时,占大头的都是char[] ,byte[]之类的,没什么用(用jmap -histo:live pid 看的也是本身大小)。所以需要关心的是保留大小比较大的对象,看谁在引用这些char[], byte[]。
注意事项:
1,jmap -dump这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。
2,jmap -histo:live这个命令执行,JVM会先触发gc,然后再统计信息。
1) jstat -gcutil 1000 查看full gc执行的次数;
2) jmap -histo:live 执行这个命令;
3) jstat -gcutil 1000 查看full gc执行的次数,结果增加了一次;
以上是关于20210520 使用jmap分析虚拟机内存状况的主要内容,如果未能解决你的问题,请参考以下文章