分析思路

image.png

Java 类应用查找方法执行时间

文章介绍的不详细, 这里仅列出我推荐的技术手段, 具体使用方式需要时再学

jvisualvm

JMC

Arthas

Java类应用查找对象内存消耗

内存趋势判断

内存泄漏示意图
image.png

此处还是拿jvisualvm示例
示例一, 典型的正常内存的场景
image.png

  1. 内存使用很正常,回收健康。
  2. 内存从目前的压力级别上来看,够用,无需再增加。
  3. 无内存泄露的情况,因为回收之后基本回到了同一水位上。
  4. 基本也能看得出来 GC 够快。为什么说基本呢?因为最好还是看一下这张图。

image.png
从这张图可以看到,当应用在压力场景之后,GC 并没有消耗过多的 CPU。

示例二, 典型的内存分配过多的场景
image.png

  1. 内存使用很正常,回收健康。
  2. 从目前的压力级别上来看,内存不仅够用,而且过多。
  3. 无内存泄露的情况。

示例三, 典型的内存不够用的场景
image.png

  1. 内存使用很正常,回收健康。
  2. 从目前的压力级别上来看,内存不够用,需再增加。
  3. CPU 可看可不看,因为现在看似乎没多大意义,先加了内存再说。
  4. 无内存泄露的情况,因为回收之后基本回到了同一水位上。

示例四, 典型的内存泄露到爆的场景
jstack打印结果
image.png

  1. 年轻代(第三列)、年老代(第四列)全满了,持久代在不断增加,并且也没有释放过。
  2. 两个保留区(第一列、第二列)都是空的。
  3. Yonug GC(第六列)已经不做了。
  4. Full GC(第八列)一直都在尝试做回收的动作,但是一直也没成功,因为年轻代、年老代都没回收下来,持久代也在不停涨。

如果出现了 1 和 2 的话,不用看什么具体对象内存的消耗,只要像网上那些只玩 JVM 参数的人一样,调调参数就行了。
但是如果出现 3 和 4,对于 3 还要再判断一下,之前的内存是不是设置得太小了?如果是,就调大,看能不能到场景一的状态。如果不是,那就得像场景四一样,查一下内存到底消耗在哪个对象上了。

查找增加的内存

逻辑一, 观察FullGC后未被回收的对象

示例, 先过滤包, 点击Deltas, 拿到对象数据, 此时为0bytes
image.png
然后加压, 观察对象占用的内存上升
image.png
当内存正常回收后, 再观察Deltas, 应该能看到大部分对象都回收了的状态
image.png
若停止压力, 又做了正常的FullGC之后, 如下图
image.png
即可从图中找到无法回收的造成内存泄漏的对象

逻辑二: 从jmap的headdump中分析占用

示例, 从dump中分析出第一个可疑内存泄漏点就占用了466M的内存
image.png
详细分析, 内存消耗点多的内容
image.png
从图中可以看出这个实体Bean, 有79w个, 是导致内存泄漏的原因, 后续再看它的栈, 分析导致对象过多的具体的方法…

总结
不管是什么语言的应用,在性能分析的过程中,都是分析两个方法。

  1. 执行速度够不够快。只有够快才能满足更高的 TPS。
  2. 执行过程中内存用得多不多。内存用得少,才可以同时支持更多的请求。