21.jvm内存结构部分——堆_内存诊断_jvisualvm

好,接下来呢我们再介绍一个案例。

这个案例呢就有一定的实际应用价值,

嗯就是我有一个应用程序,它在执行多次垃圾回收以后,内存占用仍然很高啊,这是它的一个现象。那我们针对这种现象,我们来看怎么利用工具来进行排查。


好,这里呢我已经把这个程序运行起来了啊,你并不知道这个程序代码是怎么写的。那么借助一些工具先来看一下,比如说我们学过一个jmap工具啊,

加上先来jps 啊,先看看那个进程id啊,进程id 我们看一下它是16540啊这个进程。好,那我们来jmap -heap 16540。

C:\Users\89296\IdeaProjects\studyjava>jmap -heap 16540
Attaching to process ID 16540, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b15

using thread-local object allocation.
Parallel GC with 10 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4253024256 (4056.0MB)
   NewSize                  = 88604672 (84.5MB)
   MaxNewSize               = 1417674752 (1352.0MB)
   OldSize                  = 177733632 (169.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 133169152 (127.0MB)
   used     = 91035960 (86.81865692138672MB)
   free     = 42133192 (40.18134307861328MB)
   68.36114718219427% used
From Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
To Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
PS Old Generation
   capacity = 274726912 (262.0MB)
   used     = 126876568 (120.9989242553711MB)
   free     = 147850344 (141.0010757446289MB)
   46.18279551731721% used

3155 interned Strings occupying 258800 bytes.


看一下它的这个使用情况啊,看一下它的Eden ,就是它的一个内存区占用了呃86兆,三十三兆我们还得注意观察一下一个老年代Old Generation。啊,老年代他是另一部分内存占用的地方,占用了大约120兆。那我们发现大约总共的内存占用是206兆左右。

那我们执行一次垃圾回收试一下啊。
这里我用jconsole工具吧。



jconsole的工具连到这个进程上。


嗯,在内存这个选项卡里有一个叫执行jc 啊这样一个动作。执行一下。


哎,可以看到这个内存下降了很多,但实际上下降的真的很多吗?

 不是,你看它刚开始量是235兆多,然后执行垃圾回收以后,大约还是有两百多兆。那我们再jmap 重新看一下。

C:\Users\89296\IdeaProjects\studyjava>jmap -heap 16540
Attaching to process ID 16540, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b15

using thread-local object allocation.
Parallel GC with 10 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4253024256 (4056.0MB)
   NewSize                  = 88604672 (84.5MB)
   MaxNewSize               = 1417674752 (1352.0MB)
   OldSize                  = 177733632 (169.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 133169152 (127.0MB)
   used     = 11909664 (11.357940673828125MB)
   free     = 121259488 (115.64205932617188MB)
   8.943260373093011% used
From Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
To Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
PS Old Generation
   capacity = 274726912 (262.0MB)
   used     = 212392920 (202.55367279052734MB)
   free     = 62333992 (59.446327209472656MB)
   77.31056213378906% used

5615 interned Strings occupying 466544 bytes.


可以看到啊,新生代确实内存被回收掉了不少啊,剩了八兆。那老年代呢它是还有两百多兆,还有两百零二兆。那我们就很奇怪啊,为啥这个内存一直没有回收掉呢?是不是有一些由于我们的一些编程失误,导致了很一些对象始终被引用而无法释放他们的内存呢?好,这里我再给大家介绍一个更好用的工具,叫jvisualvm。

 

 这里我重启了下程序后续,pid都是28520了哈

 
连上去以后呢,呃我们可以看到它的这个功能啊,跟我们刚才的jconsole有点像,它也可以监测我们一个内存的占用啊,可以看到这是堆内存占用啊,现在大约是两百多兆。

然后它也可以执行一些垃圾回收的操作啊,它也可以监测线程,这种也是可视化的方式啊,去看看啊堆的各个组成部分,它的内存占用。

 

 这里呢我要介绍它的一个很好用的功能,它叫做堆dump

 他就是也是抓取这个堆的当前快照啊,然后呢我们可以进一步对里面的一些详细内容进行分析。这是刚才的jmap,包括这个接jconsole 工具啊所不具备的。

我们点击一下这个。


它就是把那一时刻堆的内存信息给它截取下来了。

并且这个堆里面有哪些类型的对象,每个对象的个数,这些信息它也会收集起来。
好,我们怎么用呢?

大家可以看到它的这有个检查,检查这儿它有个功能是查找保留前20个保留大小最大的对象啊,意思就是让我看看哪些对象添加内存呢,把前二十个把它找出来。好,我们点击查找。

 


这里呢他说由于这个堆比较大,那么可能会操呃需要很长的时间。是不是要继续,我们选择是。
好,可以看到我们这个结果出来了。
最大的一个占用空间最大的一个类啊是一个好像是一个arraylist。
好,那既然是它比较大,那我们不妨点击进去看一下。


好在这里我们可以看到这个array list 它的一些详细信息啊,它占了刚才我们看到它占了209兆。那它为什么占了这么大呢?我们可以看一下它里面包含了什么元素,它的elementData也包含了这个arraylist所有的元素啊,可以看到它包含的是什么呀。
而包含那些student 的对象。那我们就定位到了哦,可能是它是个student 的对象,是不是占用的内存比较大呢?我们打开一个看一下。

 

好,可以看到这个student 的对象中有一个属性叫做big 这样一个属性,它是一个byte数组。这个byte数组呢占用的空间大小在这大约是一兆左右。

那整个我们这个arraylist 它的一个数量,我们从size 属性中看出了size为200.也就是这里有两百个student 对象嘛,每个student 对象这样呢有一兆的内存,两百个,那不就是两百多兆吗?


好,那我们就排查出来了啊,肯定是你这个student 的对象以及这个list 导致我们的内存占用比较高。而且它这个对象是长时间使用的,导致垃圾回收,没办法回收他们的内存。
好,我们回过头来看一下我们的源代码,看看是不是这样。


好,我们读一下这段代码。果然啊这个student 的对象中有一个big 的属性,里面的大小是1兆。那这样的student 对象有多少呢?我们循环了两百次啊,把它都加到了一个list 中。

而这个list 由于它一直在main方法里啊,而main方法一直没结束,所以都是在它的这个生存范围内啊,所以它一直没能被回收,就导致我们的内存占用居高不下。

当然这个例子是刻意做出来的,但实际的这个生产环境下分析的这个手段和可排查的这种方式啊也是类似的。我们现在也是通过这个堆转储功能(堆dump)。
这个功能也就是咱们看到那个dump 功能去把这个内存快照给它抓下来。抓下来以后我们分析对内存占用最大的那些对象啊,就可以得出一些有用的结论,就发现到底是哪些对象占用的内存太大。那你再去分析和排查你的原始代码就可以了。好,关于这个案例啊,我们就介绍到这。

上一篇:20.jvm内存结构部分——堆_内存诊断_jconsole_tgbyhn31的博客-CSDN博客

下一篇:22.jvm内存结构部分——方法区_定义_tgbyhn31的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值