当前位置:网站首页>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
边栏推荐
- Frequently asked interview questions - 2 (computer network)
- Find the number of "blocks" in the matrix (BFS)
- STL function library
- Parameter analysis of open3d material setting
- ‘EddiesObservations‘ object has no attribute ‘filled‘
- Excel obtains the difference data of two columns of data
- Markdown syntax support test
- js数字大写方法
- Add two pointers? (legal or illegal)
- 【华为机试】考试得分总数(如何处理答错的情况?回溯一次,代表答错一题)
猜你喜欢

jdbc入门\获取数据库连接\使用PreparedStatement

2-软件设计原则

Find the number of "blocks" in the matrix (BFS)

QT drawpixmap and DrawImage blur problem

‘EddiesObservations‘ object has no attribute ‘filled‘

MySQL的锁机制

AcWing 836. Merge set (merge set)

Pilotage growth · ingenuity empowerment -- yonmaster developer training and pilotage plan is fully launched

基于ssm 包包商城系统

STL learning notes 0x0001 (container classification)
随机推荐
excel获取两列数据的差异数据
Interview Basics
QT drawpixmap and DrawImage blur problem
Common interview questions - 4 (MySQL)
shell指令学习1
Excel sets row and column colors according to cell contents
TypeScript interface & type 粗略理解
Ora: 28547 connection to server failed probable Oracle net admin error
多个一维数组拆分合并为二维数组
Several examples of pointer transfer, parameter transfer, value transfer, etc
AcWing 836. Merge set (merge set)
jdbc入门\获取数据库连接\使用PreparedStatement
SQL语句简单优化
数据安全入门产品——数据库审计系统详解
MySQL transaction
X86 assembly syntax: at & T and Intel
The address value indicated by the pointer and the value of the object indicated by the pointer (learning notes)
Similarities and differences between vector and array (notes)
基于ssm 包包商城系统
PHP处理json_decode()解析JSON.stringify