JVM 泄露或溢出常见问题

总结

在JVM 出现性能问题的时候。(表现上是 CPU100% ,内存一直占用)

1、 如果CPU的100%,要从两个角度出发,一个有可能是业务线程疯狂运行,比如说想很多死循环还有一种可能性,就是GC线程在疯狂的回收,因为JVM中垃圾回收器主流也是多线程的,所以很容易导致CPU的100%;

2、 在遇到内存溢出的问题的时候,一般情况下我们要查看系统中哪些对象占用得比较多,我的是一个很简单的代码,在实际的业务代码中,找到对应的对象,分析对应的类,找到为什么这些对象不能回收的原因,就是我们前面讲过的可达性分析算法,JVM的内存区域,还有垃圾回收器的基础,当然,如果遇到更加复杂的情况,你要掌握的理论基础远远不止这些(JVM很多理论都是排查问题的关键);

常见问题分析

超大对象

代码中创建了很多大对象 , 且一直因为被引用不能被回收,这些大对象会进入老年代,导致内存一直被占用,很容易引发 GC 甚至是 OOM

超过预期访问量

通常是上游系统请求流量飙升,常见于各类促销 / 秒杀活动,可以结合业务流量指标排查是否有尖状峰值。 比如如果一个系统高峰期的内存需求需要 2 个 G 的堆空间,但是堆空间设置比较小,导致内存不够,导致 JVM 发起频繁的 GC 甚至 OOM 。

过多使用 Finalizer

过度使用终结器( Finalizer ),对象没有立即被 GC , Finalizer 线程会和我们的主线程进行竞争,不过由于它的优先级较低,获取到的 CPU 时间较少,因此 它永远也赶不上主线程的步伐,程序消耗了所有的可用资源,最后抛出 OutOfMemoryError 异常。

内存泄漏

大量对象引用没有释放, JVM 无法对其自动回收。

长生命周期的对象持有短生命周期对象的引用

例如将 ArrayList 设置为静态变量,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏

连接未关闭

如数据库连接、网络连接和 IO 连接等,只有连接被关闭后,垃圾回收器才会回收对应的对象。

变量作用域不合理

例如,1. 一个变量的定义的作用范围大于其使用范围, 2. 如果没有及时地把对象设置为 null

内部类持有外部类

Java 的非静态内部类的这种创建方式,会隐式地持有外部类的引用,而且默认情况下这个引用是强引用,因此,如果内部类的生命周期长于外部类的生命 周期,程序很容易就产生内存泄漏 如果内部类的生命周期 长于 外部类的生命周期,程序很容易就产生内存泄漏(垃圾回收器会回收掉外部类的实例,但由于内部类持有外部类的引用,导 致垃圾回收器不能正常工作)

解决方法:你可以在内部类的内部显示持有一个外部类的软引用 ( 或弱引用 ) ,并通过构造方法的方式传递进来,在内部类的使用过程中,先判断一下外部 类是否被回收;

Hash 值改变

在集合中,如果修改了对象中的那些参与计算哈希值的字段,会导致无法从集合中单独删除当前对象,造成内存泄露(有代码案例 Node 类)

请先 登录 后评论
  • 0 关注
  • 0 收藏,29 浏览
  • 石天 提出于 2025-11-04 09:55

相似问题