内存泄漏的根本原因

2023-07-28 jvm

内存泄漏:程序运行期间分配的对象,用完之后却没有被GC回收,始终占用着内存,既用完弃用后又无法gc回收就发生了内存泄露。

java内存泄漏的根本原因是长命周期的对象持有短生周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

# 常见的内存泄漏场景

  1. 静态集合类引起的内存泄漏:集合是静态的,但是他们所存储的对象可能只在短时间内用到,用完后根据业务情况将其手动删除。
  2. 单例模式引起的内存泄漏:由于单例的静态特性使得其生命周期跟应用的生命周期一样长,所以如果使用不恰当的话,很容易造成内存泄漏。
  3. 常见的tcp连接引发的内存泄漏:网络连接(socket)和IO连接,除非其显式的调用了其close()方法将其连接关闭,否则不会被GC回收,注意在finally里释放连接即可。

# 内存溢出和内存泄漏的区别

  • 内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;
  • 内存泄漏是程序运行期间分配的对象,用完之后却没有被GC回收,始终占用着内存,既用完弃用后又无法gc回收就发生了内存泄露。一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光,最终演变成内存溢出。

# 有哪些常见的内存溢出?如何解决?

  1. java.lang.OutOfMemoryError: Metaspace (方法区溢出)

    我们知道jvm通过持久代实现了java虚拟机规范中的方法区,而运行时常量池就是保存在方法区中的,因此发生这种溢出可能是运行时常量池溢出,或是由于程序中使用了大量的jar或class,使得方法区中保存的class对象没有被及时回收或者class信息占用的内存超过了配置的大小。

  2. java.lang.OutOfMemoryError: Java heap space (堆溢出)

    发生这种溢出的原因一般是创建的对象太多,在进行垃圾回收之前对象数量达到了最大堆的容量限制。解决这个区域异常的方法一般是通过内存映像分析工具对Dump出来的堆转储快照进行分析,看到底是内存溢出还是内存泄漏。

    • 如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,定位出泄漏代码的位置,修改程序或算法;
    • 如果不存在泄漏,就是说内存中的对象确实都还必须存活,那就应该检查虚拟机的堆参数-Xmx(最大堆大小)和-Xms(初始堆大小),与机器物理内存对比看是否可以调大。
  3. 虚拟机栈和本地方法栈溢出:如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError。

上次更新: 6 个月前