内存泄漏和内存溢出

1.内存泄漏 (Memory Leak)

1. 定义

内存泄漏是指程序未能释放已经不再使用的内存,从而导致内存资源被浪费。尽管这些内存不再被程序使用,但由于程序仍然持有对它们的引用,垃圾收集器无法回收它们。

2. 症状

  • 随着时间推移,程序占用的内存不断增加。
  • 程序可能在长时间运行后变得越来越慢。
  • 最终可能导致内存溢出错误(OutOfMemoryError)。

3. 原因

  • 忘记移除不再使用的对象引用。
  • 使用静态集合(如 HashMapArrayList)时未及时清理其中的对象。
  • 事件监听器、回调函数未解除绑定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.ArrayList;
import java.util.List;

public class MemoryLeakExample {
private List<Object> objectList = new ArrayList<>();

public void addObject(Object obj) {
objectList.add(obj); // 对象一直被添加进集合中,但未被移除
}

public static void main(String[] args) {
MemoryLeakExample example = new MemoryLeakExample();
while (true) {
example.addObject(new Object());
}
}
}

2. 内存溢出 (OutOfMemoryError)

1. 定义

内存溢出是指程序在请求内存时,堆内存已满且垃圾收集器无法回收更多的内存,从而导致 JVM 抛出 OutOfMemoryError 错误。

2. 症状

  • 程序突然崩溃并抛出 OutOfMemoryError

  • 无法再分配新的对象。

3. 原因

  • 创建了过多的大对象或集合。
  • 内存泄漏导致的内存占用持续增加。
  • JVM 堆内存设置不足以满足应用的需求。
1
2
3
4
5
6
7
8
9
10
11
12
import java.util.ArrayList;
import java.util.List;

public class OutOfMemoryErrorExample {
public static void main(String[] args) {
List<int[]> list = new ArrayList<>();
while (true) {
list.add(new int[1000000]); // 不断创建大数组,导致内存耗尽
}
}
}

3. 区别

内存泄漏

  • 由于程序错误,内存未被正确释放。
  • 内存使用量随时间增加,最终可能导致内存溢出。
  • 可以通过分析程序逻辑和使用工具(如 VisualVM、MAT)定位未释放的内存。

内存溢出

  • 直接结果是 JVM 无法分配内存,抛出 OutOfMemoryError
  • 可能是内存泄漏的结果,也可能是程序需要的内存超过了 JVM 配置的最大堆内存。
  • 可以通过调整 JVM 堆内存大小(如 -Xmx 参数)和优化程序内存使用来解决。

4 OOM等内存分析

  • 方式: 检查是否有OutOfMemory 等内存异常, 检查哪些对象在系统中数量最大,避免频繁生成新对象,类似天气预报系统里有一个分页展示,每次批量去操作5000个对象,会频繁触发Minor GC 和 Full GC,后面调成500个,基本上就没有Full GC了。
  • 工具:jmap ‐dump,生成Java虚拟机的堆转储快照dump文件,用jvisualvm命令工具导入该dump文件分析,最多的类是哪些
  • 参考地址:java命令–jmap工具 - 楼上有只喵 (pyr9.github.io)

5 CPU分析,哪些方法占用的大量CPU时间

  • 方式:
    • 命令top -p ,显示你的java进程的内存情况,找到当前进程的PID
    • top -Hp,获取每个线程的内存情况,获取CPU比较高的线程id,并专成16进制
    • 执行 jstack PID|grep -A 10 4cd0得到线程堆栈信息,找出可能存在问题的代码,比如大量计算,或者循环new 对象

内存泄漏和内存溢出
http://example.com/内存泄漏和内存溢出/
作者
Panyurou
发布于
2024年6月13日
许可协议