当前位置:网站首页>JVM系列(4)——内存溢出(OOM)
JVM系列(4)——内存溢出(OOM)
2022-04-23 05:41:00 【李王家的翠花】
一、内存泄露与内存溢出
内存泄露(memory leak):是指本应该被GC回收的无用对象没有被回收,导致的内存空间的浪费,当内存泄露严重时会导致OOM(内存溢出简称,下文称OOM)。
Java内存泄露根本原因是:长生命周期的对象持有短生命周期对象的引用,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被GC回收。(这篇文章不做详细的举例介绍,后面总结完垃圾回收机制之后,进行详细的举例分析)
内存溢出 (out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现OOM。比如申请了一个int,但给它存了long才能存下的数,那就是内存溢出。
本文连接上文JVM系列(1)——java内存区域从各个内存区域可能发生的OOM和栈溢出异常(StackOverflowException)具体举例进行说明,并提供相应的解决办法。
栈内存溢出(StackOverflowError):程序所要求的栈深度过大导致。
二、idea设置jvm内存参数
我们利用idea进行jvm内存参数的设置,以进行异常测试。如图所示:
二、堆内存溢出
java堆用来存储对象实例,不断的创建对象而不去GC,当对象内存占用达到堆最大值的限制后,就会发生内存溢出。
/** * -Xms5m 最大可用内存 * -Xmx5m 初始内存 */
public class HeapOOM {
public static void main(String[] args) {
int count = 0;
List<Object> list = new ArrayList<Object>();
while(true){
list.add(new Object());
System.out.println(++count);
}
}
运行结果,在160065个对象后,发生OOM:
160065
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:265)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
at java.util.ArrayList.add(ArrayList.java:462)
at com.jvm.HeapOOM.main(HeapOOM.java:16)
随着-Xmx参数值的增大,java堆中可以存储的对象也越多。
三、虚拟机栈和本地方法栈溢出
对于HotSpot虚拟机来说,栈容量只有-Xss参数设置(HotSpot虚拟机不区分虚拟机栈和本地方法栈)。
(1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;
(2)如果虚拟机栈扩展时无法申请到足够的内存时会抛出 OutOfMemoryError 异常。
package com.jvm;
public class JvmStackSOF {
private int stackLength = 1;
//反复调用
public void stackLeak() {
stackLength++;
stackLeak();
}
/** * -Xss128k 栈内存容量 */
public static void main(String[] args) throws Throwable {
JvmStackSOF oom = new JvmStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
运行结果如下:
stack length:11415
Exception in thread "main" java.lang.StackOverflowError
at com.jvm.JvmStackSOF.stackLeak(JvmStackSOF.java:8)
at com.jvm.JvmStackSOF.stackLeak(JvmStackSOF.java:9)
at com.jvm.JvmStackSOF.stackLeak(JvmStackSOF.java:9)
at com.jvm.JvmStackSOF.stackLeak(JvmStackSOF.java:9)
at com.jvm.JvmStackSOF.stackLeak(JvmStackSOF.java:9)
在单个线程下,无论是由于栈帧太大,还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是 StackOverflowError 异常,而不是OOM。
如果是多线程的情况下,不断建立线程,会出现OOM。代码如下:
package com.jvm;
public class JvmStackSOF {
/** * -Xss2M 栈内存容量 */
private void dontStop() {
while (true) {
}
}
public void stackLeakByThread() {
while (true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JvmStackSOF oom = new JvmStackSOF();
oom.stackLeakByThread();
}
}
运行结果如下:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at com.jvm.JvmStackSOF.stackLeakByThread(JvmStackSOF.java:21)
at com.jvm.JvmStackSOF.main(JvmStackSOF.java:27)
这种情况下产生的内存溢出异常与栈空间是否足够大并不存在任何联系,或者准确地说,在这种情况下,给每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。
原理如图:
操作系统分配给每个进程的内存是有限制的,譬如 32 位的 Windows 限制为 2GB。虚拟机提供了参数来控制 Java 堆和方法区的这两部分内存的最大值。剩余的内存为 2GB(操作系统限制)减去 Xmx(最大堆容量),再减去 MaxPermSize(最大方法区容量),程序计数器消耗内存很小,可以忽略掉。如果虚拟机进程本身耗费的内存不计算在内,剩下的内存就由虚拟机栈和本地方法栈“瓜分”了。每个线程分配到的栈容量越大,可以建立的线程数量自然就越少,建立线程时就越容易把剩下的内存耗尽。
解决方案:出现栈内存OOM,在不能减少线程数或者更换 64 位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。
版权声明
本文为[李王家的翠花]所创,转载请带上原文链接,感谢
https://blog.csdn.net/liwangcuihua/article/details/120162420
边栏推荐
猜你喜欢
Breadth first search topics (BFS)
‘EddiesObservations‘ object has no attribute ‘filled‘
SQL statement simple optimization
deep learning object detection
AcWing 836. Merge set (merge set)
Data mining -- understanding data
mysql实现主从复制/主从同步
Hongji micro classroom | cyclone RPA's "flexible digital employee" actuator
2-軟件設計原則
Flutter 新一代图形渲染器 Impeller
随机推荐
College entrance examination volunteer filling reference
shell指令学习1
POI generates excel and inserts pictures
mysql中duplicate key update
Formal parameters, local variables and local static variables
Strategies to improve Facebook's touch rate and interaction rate | intelligent customer service helps you grasp users' hearts
Shell instruction learning 1
Range of numbers (dichotomous classic template topic)
STL learning notes 0x0001 (container classification)
引航成长·匠心赋能——YonMaster开发者培训领航计划全面开启
基于ssm 包包商城系统
AcWing 836. Merge set (merge set)
Add days to date
Summary of redis classic interview questions 2022
poi生成excel,插入图片
mysql实现主从复制/主从同步
js数字大写方法
Establish excel bookkeeping book through setting context menu
数据安全入门产品——数据库审计系统详解
Relative reference and absolute reference of Excel