Eclipse Memory Analyzer调优简单入门使用
first这是jvm性能调优的第一章,其实之前也有类似的jvm调优经历,但是没有时间记录,并且堆文件已经丢失,也没有写对应的文档,就不打算写进来,所选章数,就按照最近的调优案例来排序吧。分析堆文件实际上很多工具都是可以。这是jvm调优的第一章,我尽量在以后的每一章。都使用不同的jvm调优工具。最后来个对比,分析一下各个工具的优劣性。java强引用例如我们在代码中直接给对象进行的赋值。软引用还有用,
压测内存溢出Jvm
调优总结
一、背景
1.1、first
这是jvm
性能调优的第一章,其实之前也有类似的jvm
调优经历,但是没有时间记录,并且堆文件已经丢失,也没有写对应的文档,就不打算写进来,所选章数,就按照最近的调优案例来排序吧。
1.2、起因
业务场景中有个page
查询,在正常点击和用户正常使用,并没有什么速度上的不适。并且这个功能已经上了正式好几个月了。某次更新版本的时候。测试人员工作不饱和,对该接口进行压测。发现并发量是每10秒80,然后紧接着报错,最后jvm
堆内存溢出而GG
。后续又进行了几次压测。发现10秒40次的时候,就已经G
了,简单看了一眼代码,实际上并没有真正的猜测到是哪一块导致堆内存溢出。 对于这种具有偶发性的问题,决定采用分析堆文件的方式来看看能不能找到稍微可以优化的点。
二、前期准备
2.1、工具介绍
(1)Eclipse Memory Analyzer
分析堆文件实际上很多工具都是可以。这是jvm
调优的第一章,我尽量在以后的每一章。都使用不同的jvm
调优工具。最后来个对比,分析一下各个工具的优劣性。
(2)界面
(3)设置启动堆内存
Eclipse Memory Analyzer
默认的启动堆最大内存为1G
。这一步取决你堆内存文件的大小。我这边正式环境导出的堆文件大小大概3G
多一点。所以索性我就将Eclipse Memory Analyer
,启动最大堆内存调成4G
。- 操作步骤如下。
- 文件目录。
- 修改
三、开始分析
3.1、导入堆文件
导入成功的页面
3.2、解释
- 这个工具确实是优秀,直接给你分析出对应可能导致内存泄露的几个疑点。从对应的内存占用分布图来看。我们一般直接分析对应的所占内存最大的疑点一(
problem Suspect 1
)(这里只是举个栗子,实际上分析内存泄露的原因不能这么片面,选取最大占用只是因为我当时在分析的时候是按照顺序分析的,第一个就找到了端倪)。 - 根据以下截图。我们发现这块疑点内存泄露所产生的对象均是
TaskThread
,实际上就对应了我们开始所说的进行压测。前端短时间内发起多个请求。tomcat
所创建的n条线程去处理请求。
(1)大对象
点进detail
之后,我们发现对应的大对象实际上也都是这些TaskThread
.注意,这些大对象并不是说对象本身所占的内存大,而是这个对象。所往下引用的对象所有之和所占的内存。这里设计到两个词
Shallow Head
代表的是对象本身所占的堆内存的大小。并不包括其引用的其他对象。Retained Head
代表的是这个对象及其他所关联的其他对象的所占内存的总好。
(2)对象分析
我们按照上图箭头点进去。发现tomcat 本身产生的线程对应的本身内存占用并不大。真正大的是他所引用的其他对象。
因此。我们要根据这个线程对象去找到他所引用的对象,那块是导致内存占用的罪魁祸首。
根据最后的定位。发现真真正占据内存的是一个长度为70多万的ArrayList
。其里面对象的内容为 [0]是一段字符串。[1]是一个时间参数。那么此时。我们就大概推算出导致堆内存溢出的主要原因就是这个ArrayList
。我们就可以以此去结合我们的业务代码。制定对应的优化策略
(3)结果
结合上面的所得到的信息。我去修改的了对应的业务代码,因为涉及到公司机密,这里就没法贴出代码细节。实际上就是修改了对应ArrayList
。结合对应的业务,看能不能删减一点。或者是将其用redis
暂存实现复用。如果都不行,那就牺牲时间换取空间。修改代码之后,我让测试又在测试环境进行了几次压测。在原来的条件下,进行n倍加压。都没有导致堆内存溢出。
四、工具补充
实际上在本次分析中,我们是通过Jvm
中添加了对应的启动命令,在内存溢出的那一刻生成类似于快照的堆文件,实际上并没有设计到垃圾回收方面的分析,因为本次性能优化是在并发测试下,我第一时间考虑的是内存溢出的时候是哪块对象占用这么高。从简单的tomcat
创建的请求线程,一步一步的往下摸索。其实也没有考虑对应的GcRoot
。
但是在很多实际的问题面前,我们进行JVM
调优,并不仅仅是内存溢出,又或者压测而导致机器异常负载的情况下才进行的。我时常是要分析的是jvm
,有没有因为程序员代码的问题而导致频繁的Full GC
,有没有频繁的Stop the world
。这个时候GcRoot
相关的操作就显得很重要。
4.1、引用强度介绍
(1)java
12对于引用的重新定义
-
强引用
- 例如我们在代码中直接给对象进行的赋值。
-
软引用
- 还有用,但是不是必须的。只是软引用关联着的对象。在系统要发生内存溢出之前。系统会将这些对象进行二次回收,二次回收之后,如果还是不够用,那么系统才会内存溢出
-
弱引用
- 也是那些不是必须的对象。等级需求性比软引用还要低。这些对象只能存活到下一次垃圾回收之前。无论内存是否够用,下一次内存回收都会回收他,
-
虚引用
-
幽灵引用或者是幻影引用
-
它是最弱的一种引用关系。一个对象是否有虚引用的
存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚
引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2
版之后提供
了PhantomReference
类来实现虚引用。
-
(2)工具的使用
通过对应的对于引用的定义,我们实际上就可以默认排除掉弱引用,那么剩下的就是无法被jvm
回收。如下图所示
总的而言,这个功能我觉得是挺好用的。
更多推荐
所有评论(0)