Salmon的全栈知识 Salmon的全栈知识
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • Gateway
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • Gateway
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
npm

(进入注册为作者充电)

  • JVM基础

    • 初识JVM
    • 字节码文件详解
    • 运行时数据区
    • 垃圾回收
  • JVM实战

    • 内存调优
    • GC调优
    • 性能调优
  • JVM高级

    • GraalVM
    • 新一代的GC
    • 揭秘Java工具
  • JVM原理

    • 栈上的数据存储
    • 对象在堆上是如何存储的?
    • 方法调用的原理
    • 异常捕获的原理
    • JIT即时编译器
    • 垃圾回收器原理
  • JVM面试

    • 什么是JVM?
    • 了解过字节码文件的组成吗?
    • 说一下运行时数据区
    • 哪些区域会出现内存溢出,会有什么现象?
    • JVM在JDK6-8之间在内存区域上有什么不同
    • 类的生命周期
    • 什么是类加载器?
    • 什么是双亲委派机制
    • 如何打破双亲委派机制
    • Tomcat的自定义类加载器
    • 如何判断堆上的对象没有被引用??
    • JVM 中都有哪些引用类型?
    • ThreadLocal中为什么要使用弱引用?
    • 有哪些常见的垃圾回收算法?
    • 有哪些常用的垃圾回收器?
    • 如何解决内存泄漏问题?
      • 发现问题 – 堆内存状况的对比
      • 诊断 – 生成内存快照
      • 诊断 – MAT定位问题
      • 修复问题
      • 常用的JVM工具
    • 常见的JVM参数?
  • 《JVM》笔记
  • JVM面试
Salmon
2024-03-12
目录

如何解决内存泄漏问题?

  • 关联课程内容

    • 实战篇-内存泄漏和内存溢出
    • …
    • 实战篇-btrace和arthas在线定位问题
  • 回答路径

    • 内存泄漏和内存溢出
    • 解决内存泄漏问题的思路
    • 常用的工具

内存泄漏(memory leak):在Java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收,这种情况就称之为内存泄漏。

少量的内存泄漏可以容忍,但是如果发生持续的内存泄漏,就像滚雪球雪球越滚越大,不管有多大的内存迟早会被消耗完,最终导致的结果就是内存溢出。

img

解决内存泄漏问题总共分为四个步骤,其中前两个步骤是最核心的:

img

# 发现问题 – 堆内存状况的对比

正常情况

img

  • 处理业务时会出现上下起伏,业务对象频繁创建内存会升高,触发MinorGC之后内存会降下来。
  • 手动执行FULL GC之后,内存大小会骤降,而且每次降完之后的大小是接近的。
  • 长时间观察内存曲线应该是在一个范围内。

出现内存泄漏

img

  • 处于持续增长的情况,即使Minor GC也不能把大部分对象回收
  • 手动FULL GC之后的内存量每一次都在增长
  • 长时间观察内存曲线持续增长

生产环境通过运维提供的Prometheus + Grafana等监控平台查看

开发、测试环境通过visualvm查看

package q7oom;

import java.util.ArrayList;
import java.util.List;

//-Xmx10m -verbose:gc
public class OOMDemo {
    private static int _1MB = 1024 * 1024 * 1;
    public static void main(String[] args) throws InterruptedException {
        List<Object> objects = new ArrayList<>();

        while (true){
            byte[] bytes = new byte[_1MB];
            //强引用
            objects.add(bytes);
            Thread.sleep(50);
        }

    }
}

这段代码执行之后,使用visualvm查看结果:

img

处于持续增长的情况,手动FULL GC之后的内存量每一次都在增长,长时间观察内存曲线持续增长。属于内存泄漏的情况。

# 诊断 – 生成内存快照

当堆内存溢出时,需要在堆内存溢出时将整个堆内存保存下来,生成内存快照(Heap Profile )文件。

生成方式有两种

1、内存溢出时自动生成,添加生成内存快照的Java虚拟机参数:

​ -XX:+HeapDumpOnOutOfMemoryError:发生OutOfMemoryError错误时,自动生成hprof内存快照文件。

​ -XX:HeapDumpPath=<path>:指定hprof文件的输出路径。

img

发生oom之后,就会生成内存快照文件:

img

2、导出运行中系统的内存快照,比较简单的方式有两种,注意只需要导出标记为存活的对象:

通过JDK自带的jmap命令导出,格式为:

​ jmap -dump:live,format=b,file=文件路径和文件名 进程ID

通过arthas的heapdump命令导出,格式为:

​ heapdump --live 文件路径和文件名

img

# 诊断 – MAT定位问题

使用MAT打开hprof文件,并选择内存泄漏检测功能,MAT会自行根据内存快照中保存的数据分析内存泄漏的根源。

img

# 修复问题

修复内存溢出问题的要具体问题具体分析,问题总共可以分成三类:

  • 代码中的内存泄漏,由于代码的不合理写法存在隐患,导致内存泄漏
  • 并发引起内存溢出 - 参数不当,由于参数设置不当,比如堆内存设置过小,导致并发量增加之后超过堆内存的上限。解决方案:设置合理参数
  • 并发引起内存溢出 – 设计不当,系统的方案设计不当,比如:
    • 从数据库获取超大数据量的数据
    • 线程池设计不当
    • 生产者-消费者模型,消费者消费性能问题

​ 解决方案:优化设计方案

# 常用的JVM工具

JDK自带的命令行工具:

jps 查看java进程,打印main方法所在类名和进程id

jmap 1、生成堆内存快照

​ 2、打印类的直方图

第三方工具:

VisualVM 监控

Arthas 综合性工具

MAT 堆内存分析工具

监控工具:

Prometheus + grafana

上次更新: 2025/03/09, 18:29:07
有哪些常用的垃圾回收器?
常见的JVM参数?

← 有哪些常用的垃圾回收器? 常见的JVM参数?→

Theme by Vdoing | Copyright © 2022-2025 Salmon's Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式