内存泄漏和内存溢出
文章目录
相关文章:
JVM内存模型
Java GC垃圾回收机制
一、内存泄漏
Memory Leak,内存泄漏,在 JAVA 语言中指的是申请的内存空间不能被正常回收,导致后续程序里这块内存被永远占用(不可达),当指向这块内存空间的指针不再存在时,这块内存也就永远不可达了,这块内存空间就被泄漏了。
一般情况下,少量的内存泄漏不会有什么影响,但是长期大量的内存泄漏可能会引起内存溢出。
借用别人的比喻就是:
比如有 10 张纸,本来一人一张,画完自己擦了还回去,别人可以继续画。
现在有个坏蛋要了纸不还,然后还跑了找不到人了,如此就只剩下 9 张纸给别人用了。
这种情况就相当于 "内存泄漏" 了。
这种不道德的人多了,最后纸都 "泄漏" 完了,再有人来要纸就没有了,就变成 "内存溢出" 了。
在 C/C++ 中,程序员动态申请的内存空间通常需要人为调用 free/delete 来释放,否则内存会一直被占用,不会自动释放,于是就很容易造成内存泄漏。
而在 Java 中,JVM GC 垃圾回收机制会自动回收不可达对象,不需要程序员手动释放空间,大大减少了内存泄漏的可能性。
二、内存溢出
内存溢出,其实就是内存越界,是指存储的数据超出了可分配的空间大小,这时程序就会出现内存溢出错误。
内存溢出通常是内存不足,内存泄漏通常是指内存空间没有正常回收或无法回收。
在 JAVA 语言中,内存溢出包括两类情况:
-
*Error
:通常是栈深度不足导致的栈内存溢出 -
OutOfMemoryError
:通常是内存空间不足导致的内存溢出
1、*
*
,通常称为栈溢出。
先看一下之前的文章中讲过的 JVM 的内存模型,如下图所示:
在 Java 中,栈是由许多栈帧(Stack frame)组成,一个栈帧包含一个 Java 方法的调用状态。
执行每个方法时都会在调用栈上分配一个栈帧 (Stack Frame),用于存储引用方法的参数、方法中定义的变量、操作数栈、方法的返回地址等信息。
栈帧随着方法调用而创建,随着方法结束而销毁。
如果在调用方法时,线程请求的栈深度大于 JVM 允许的深度,就会抛出 *Error
栈溢出错误。(最常见的可能耗光 Java 栈深度的场景是方法递归)
2、OutOfMemory
OutOfMemoryError
,简称 OOM。
很多时候会认为内存溢出就是指 OOM,其实二者并不等价,只能说因为 OOM 引起内存溢出的情况比较多一些。
在 Java 中,
出现 OOM 最多的就是堆内存溢出,一般是类似下面这样的报错:
java.lang.OutOfMemoryError: Java heap space
当出现类似这样的报错信息后,就要进一步排查错误日志、参数配置、代码等方面。
更多 OOM 问题的分析和解决在后面详细讲解。