内存溢出(OOM)
内存溢出是引发程序崩溃的罪魁祸首之一,当应用程序内存增长速度非常快,造成的垃圾速度已经跟不上内存消耗的速度,容易出现内存溢出问题,大多数情况下,GC会进行各种年龄段的垃圾回收,实在不行了就触发Full GC,这时候会回收大量的内存,供程序继续使用
javadoc对OutOfMemoryError的解释是:没有空闲内存,并且垃圾回收器也无法提供更多内存
没有空闲内存一般有两种情况:
- Java虚拟机的堆内存设置不够
- 代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用),比如jdk8之前的永久代,jvm对永久代很少进行垃圾回收,容易出现
OutOfMemoryError
注意:在抛出OOM异常之前,通常垃圾收集器会被触发,尽可能去清理出空间,比如在引用机制中涉及到JVM去尝试回软引用
用指向的对象,也会有垃圾收集器不会被触发的情况:比如在分配一个超大对象,jvm可以判断出垃圾收集不能解决这个问题,所以直接抛出OOM异常
内存泄漏(Memory Leak)
内存泄漏也叫存储渗漏,严格来说,只有对象不会被程序用到了,但GC又不能回收的情况,才叫内存泄漏
对比示例图,举两个java中内存泄漏的案例:
- 单例模式,单例对象的生命周期是和程序一样长的,比如lang包下的
Runtime
类,代表运行时数据环境,每个进程独有一份,如果这个对象引用到一个生命周期很短的对象,并且这个指针没有被及时断掉,GC无法回收,就会导致内存泄漏 - 一些提供
close
方法的资源类,未及时调用这些方法导致内存泄漏,比如数据库链接,io,网络链接等,必须手动close
在日常代码中,本可设置为局部变量的变量被声明为成员或类变量导致对象生命周期边变长甚至导致OOM,也可以叫做宽泛意义上的内存泄漏,内存泄漏不一定导致OOM,