JVM调优-内存调优

内存调优

什么是内存泄露

Java中如果一个对象不再被使用,但他仍在GC ROOT的引用链上,根据之前提到的回收办法,他就不会被垃圾回收器回收,这就造成了内存泄露。内存泄漏往往发生在堆区。

下面列举几个内存泄露的常见场景
  • 在Java后端程序中处理完用户请求后未及时将用户数据删除,随着用户数据不断累积,造成堆内存溢出
  • 进行分布式调度时被调度的应用在调度结束时出现了内存泄漏,多次调度后内存溢出
内存泄露的解决方案

对于内存泄露,常常按照四步来解决

image-20240118211321699

发现问题阶段

常使用阿里开发的Arthas工具来对业务状态进行监看

image-20240118211600536

而Prometheus+Grafana是企业中运维常用的监控方案

image-20240118211642843

在使用上面的工具对堆内存状况进行监看,我们可以发现出现内存泄漏时,堆内存会出现明显异常

image-20240118211749433

诊断阶段
原因1: 内存中的代码泄露
  • equals()和hashCode()的不正确使用,导致同一数据被保存多次

  • ThreadLocal的使用过程中未回收线程池中的线程;

    线程方法执行完毕后,一定要调用ThreadLocal中的remove方法来清理对象

  • 通过静态字段来保存对象,造成大量数据在静态变量中被引用,但又不被使用

    尽量减少将对象长时间保存在静态变量中; 使用单例模式时,尽量使用懒加载; SpringBoot的Bean中不要长期存放大对象,若临时使用,设定过期时间定期失效

  • 内部类引用外部类;****静态的内部类会默认持有外部类,虽然代码上没有使用外部类,但如果在别的地方使用了该静态内部类,会导致外部类也被引用,让他无法被回收,造成内存泄漏

  • String的intern方法被大量调用并保存导致内存泄漏

  • 资源没有正常关闭;

    在finally块中关闭不在使用的资源

原因2: 并发请求问题

用户在短时间内发来大量并发请求,导致处理数据的时间激增,导致大量数据堆积在内存中,造成内存溢出。

为了解决高并发请求造成的内存溢出,我们可以使用Jmeter进行并发测试,定位问题根源

内存快照

当内存溢出时,为了进行时候的分析与复盘,会将内存溢出时的整个堆内存保存下来,生成内存快照(Heap Profile)。我们可以使用MAT工具打开快照文件,并且选择内存泄漏检测,就可以自动分析数据定位内存泄漏根源

生成内存快照的JVM参数

-XX:+HeapDumpOnOutOfMemoryError:发生OutOfMemoryError错误时,自动生成hprof内存快照文件。
-XX:HeapDumpPath=<path>:指定hprof文件的输出路径

MAT内存泄漏检测的原理 :

MAT就是根据支配树(如果所有指向B的路径都经过A,就认为A支配B,按这个判定方法生成支配树),从叶子节点向根节点遍历,如果发现深堆的大小超过整个堆内存的一定比例阈值,就会将其标记成内存泄漏的“嫌疑对象”。

修复阶段

上面介绍了几种引发内存泄露的来源,对于他们,我们需要逐一分析

  • 对于代码中的内存泄露;在上一阶段中已经介绍并且提供了解决方案,这里不再赘述
  • 对于因为参数不当而在高并发引起的内存溢出;需要调整参数,在下一章节GC调优中会详细介绍
  • 对于因为设计不当而在高并发引起的内存溢出(比如拉取过大的数据库数据,线程池设计不当,消费者消费性能不足等);需要对设计方案进行优化
验证阶段

对引发内存泄漏的问题进行修复后,我们就可以使用压测工具对之前引发内存泄露的场景进行复现,验证修复的可靠性

参考资料

黑马JVM虚拟机入门到实战

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值