分析思路
Java 类应用查找方法执行时间
文章介绍的不详细, 这里仅列出我推荐的技术手段, 具体使用方式需要时再学
jvisualvm
JMC
Arthas
Java类应用查找对象内存消耗
内存趋势判断
内存泄漏示意图
此处还是拿jvisualvm示例
示例一, 典型的正常内存的场景
- 内存使用很正常,回收健康。
- 内存从目前的压力级别上来看,够用,无需再增加。
- 无内存泄露的情况,因为回收之后基本回到了同一水位上。
- 基本也能看得出来 GC 够快。为什么说基本呢?因为最好还是看一下这张图。
从这张图可以看到,当应用在压力场景之后,GC 并没有消耗过多的 CPU。
示例二, 典型的内存分配过多的场景
- 内存使用很正常,回收健康。
- 从目前的压力级别上来看,内存不仅够用,而且过多。
- 无内存泄露的情况。
示例三, 典型的内存不够用的场景
- 内存使用很正常,回收健康。
- 从目前的压力级别上来看,内存不够用,需再增加。
- CPU 可看可不看,因为现在看似乎没多大意义,先加了内存再说。
- 无内存泄露的情况,因为回收之后基本回到了同一水位上。
示例四, 典型的内存泄露到爆的场景
jstack打印结果
- 年轻代(第三列)、年老代(第四列)全满了,持久代在不断增加,并且也没有释放过。
- 两个保留区(第一列、第二列)都是空的。
- Yonug GC(第六列)已经不做了。
- Full GC(第八列)一直都在尝试做回收的动作,但是一直也没成功,因为年轻代、年老代都没回收下来,持久代也在不停涨。
如果出现了 1 和 2 的话,不用看什么具体对象内存的消耗,只要像网上那些只玩 JVM 参数的人一样,调调参数就行了。
但是如果出现 3 和 4,对于 3 还要再判断一下,之前的内存是不是设置得太小了?如果是,就调大,看能不能到场景一的状态。如果不是,那就得像场景四一样,查一下内存到底消耗在哪个对象上了。
查找增加的内存
逻辑一, 观察FullGC后未被回收的对象
示例, 先过滤包, 点击Deltas, 拿到对象数据, 此时为0bytes
然后加压, 观察对象占用的内存上升
当内存正常回收后, 再观察Deltas, 应该能看到大部分对象都回收了的状态
若停止压力, 又做了正常的FullGC之后, 如下图
即可从图中找到无法回收的造成内存泄漏的对象
逻辑二: 从jmap的headdump中分析占用
示例, 从dump中分析出第一个可疑内存泄漏点就占用了466M的内存
详细分析, 内存消耗点多的内容
从图中可以看出这个实体Bean, 有79w个, 是导致内存泄漏的原因, 后续再看它的栈, 分析导致对象过多的具体的方法…
总结
不管是什么语言的应用,在性能分析的过程中,都是分析两个方法。
- 执行速度够不够快。只有够快才能满足更高的 TPS。
- 执行过程中内存用得多不多。内存用得少,才可以同时支持更多的请求。