性能文章>不起眼,但是足以让你有收获的JVM内存分析案例>

不起眼,但是足以让你有收获的JVM内存分析案例原创

5年前
118911569
作者关联了问题:
5回复
已解决

分析

这个问题说白了,就是说有些int[]对象不知道是哪里来的,于是我拿他的例子跑了跑,好像还真有这么回事。点该 dump 文件详情,查看相关的 int[] 数组,点该对象的“被引用对象”,发现所有的对象都是待回收的状态,即也没有被任何对象引用,确实很蹊跷。看了他的例子确实没有任何地方有 new int[] 的地方。

柳暗花明

由于内存 dump 文件通过 jmap 获取,于是自然就开始怀疑jmap了,难道是因为jmap导致的?所以我开始check jmap的实现,包括JDK和JVM里的逻辑,我要找到哪里可能会创建int数组,JDK层面基本可以忽略,因为实在想不到会有啥逻辑可能会有int数组产生,只是发了个命令给JVM进程而已,于是我重点分析JVM层面的实现,当我们使用jmap做了一次dump的时候或者gc发生的时候都会走到下面的逻辑,代码位置:hotspot/src/share/vm/gc_interface/collectedHeap.cpp
image.png
因为GC或者内存dump,都必须对内存做一个遍历,因此必须先暂停这些Java线程,防止在遍历内存里的对象的时候进行内存分配,但是每个线程分配内存其实都是优先走tlab(每个线程独有的一块在eden里的小内存块)的,为了能快速遍历对象,而不存在不连续的内存,于是JVM会对tlab做一个填充,填充的正好是int数组对象(从上面代码得知),将剩下的没被分配的tlab内存给填满了,因此在系统运行过程中其实可能伴随着很多无用的对象产生,哈哈,看到这里你是不是豁然开朗?

你是否可以解释如下问题了?

  • 线程越多,int数组增长越快
  • 没有分配byte数组,int数组增长很慢,甚至不增长?
  • jmap其实也不是唯一的因素

这个案例还是非常有意思的,如果还有其他问题的,也欢迎大家留言讨论。

点赞收藏
你假笨

通过创新的技术肯定可以让这个世界变得更美好,让我们为技术而狂吧

请先登录,查看15条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

69
15