内存泄漏与内存溢出
# 内存泄漏与内存溢出
# 1 什么是内存泄漏?
指一个不再被程序使用的对象或变量一致占据在内存中。
内存泄漏的情况1:程序员创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收,这就是java中可能出现内存泄漏的情况。例如,缓存系统,我们加载了一个对象放在缓存中(例如放在全局map对象中),然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。
内存泄漏情况2:当一个对象被存进HashSet集合中,就不能修改这个对象中那些参与计算哈希值的字段。否则,修改后的哈希值与最初存储在HashSet集合中的哈希值不同,这种情况下,使用contains方法无法在HashSet中检索到对象,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄漏。
public class MemoryLeakTest {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
String s = "abc";
map.put(s, 1);
System.out.println(map.get(s)); // 1
System.out.println(map.size()); // 1
s = "aaa";
System.out.println(map.get(s)); // null
System.out.println(map.size()); // 1
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 2 什么是内存溢出(OOM)?哪些区域会OOM?
指程序运行过程中无法申请到足够的内存而导致的一种错误。常见情况:OutOfMemeryError异常。
- 虚拟机栈和本地方法栈溢出
- 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError
- 如果虚拟机在扩展时无法申请到足够的内存空间,将抛出OutOfMemoryError
- 堆溢出
- 是否出现内存泄漏,可通过工具查看泄漏对象到GC ROots的引用链。
- 如果没有内存泄漏,查看虚拟机的参数(-Xmx于-Xms)的设置是否适当,
- 方法区溢出
- 运行时常量池溢出
# 3 谈谈对OOM的认识
OOM:OutOfMemeryError,是错误,不是异常
- java.lang.StackOverflowError——栈深度大于虚拟机所允许的最大深度,无限递归。
- java.lang.OutOfMemoryError: Java heap space——堆内存不够了
- java.lang.OutOfMemoryError: GC overhead limit exceeded——GC 的回收时间过程,超过 98% 的时间都用来 GC 且回收了不到 2% 的堆内存。
- java.lang.OutOfMemoryError: Direct buffer memory
- java.lang.OutOfMemoryError: unable to create new native thread
- java.lang.OutOfMemoryError: Metaspace——元空间满了
# 3 内存溢出的原因?
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 集合类中有对对象的引用,使用完后为清空,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体。
- 启动参数内存值设定的过小。
# 4 栈溢出的原因和解决办法?
原因:
- 大量的递归调用,在不断的压入栈帧,造成站容量超过内存而导致溢出。
- 由于分配了过大的局部变量。
解决办法:
- 递归转化为非递归
- 使用静态对象替换非静态局部变量
- 增加栈堆的大小
编辑 (opens new window)
上次更新: 2023/08/20, 21:21:52