栈内存溢出
在Java内存区域的Java虚拟机栈
章节介绍过,Java虚拟机栈会发生两种异常StackOverflowError、OutOfMemoryError。
- StackOverflowError
线程请求的栈深度大于虚拟机所允许的栈深度,将抛出StackOverflowError - OutOfMemoryError
如果Java虚拟机的栈容量可以动态扩展(HotSpot无法进行扩展,因此不会因为扩展而导致OOM,但如果申请时就失败,依然会出现OOM),当扩展时无法申请到足够的内存会抛出OutOfMemoryError
本文将通过代码演示这两种异常,示例采用Win10下的JDK 8运行,不同的JDK版本可能会有不同的结果。版本信息如下:
StackOverflowError
HotSpot虚拟机中,Java虚拟机栈与本地方法栈合二为一。通过-Xss参数可以设置栈内存大小,默认值一般在1M左右。linux可通过以下命令查看默认值:
[root@faith ~]# java -XX:+PrintFlagsFinal -version | grep "intx ThreadStackSize"
intx ThreadStackSize = 1024 {pd product}
openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
上面显示的单位是kb
,与-Xss
设置时单位b
不一致。
StackOverflowError示例:
package jvm.oom;
/**
* 栈StackOverflowError测试
* <p>
* 使用递归不断增加栈帧,填满栈内存
*
* @author faith.huan 2020-01-09 22:47
*/
public class JavaStackSoe {
/**
* 栈帧计数
*/
private int frameCount = 0;
/**
* 递归调用添加栈帧,并增加计数
*/
private void addFrame() {
frameCount++;
addFrame();
}
public static void main(String[] args) {
JavaStackSoe soe = new JavaStackSoe();
try {
soe.addFrame();
} catch (StackOverflowError e) {
System.out.println("StackOverflowError..frameCount==> " + soe.frameCount);
}
}
}
执行上面代码后输出:(每次执行都会有不同结果,但相差不会太大)
StackOverflowError..frameCount==> 30215
当发生StackOverflowError
时,Java虚拟机栈状态如下,此时无法容纳更多的栈帧,所以抛出StackOverflowError
上面代码在允许动态扩展栈容量大小的虚拟机上,可能会产生不同结果。例如在Classic VM上会产生OOM,鉴于此虚拟机已停用20年就不讨论了。
OutOfMemoryError
理论上栈内存OOM可以通过不断的新建线程来模拟,因为每个线程都需要一定的栈内存,当内存接近物理机内存时,会产生OOM异常。
栈内存溢出示例代码:
package jvm.oom;
/**
* 通过不断创建线程,让虚拟机出现栈内存异常
*
* @author faith.huan 2020-01-09 22:18
*/
public class JavaStackOom {
public static void main(String[] args) throws InterruptedException {
int threadNum = 1;
while (true) {
new Thread(() -> {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t-" + (threadNum++)).start();
Thread.sleep(1);
System.out.println("threadNum = " + threadNum);
}
}
}
理论终归是理论,上面的代码在64位Win10跑了10分钟,创建了2万个线程,依然未出现OOM,只是线程超过8000时,线程创建速度下降,不同机器会有不同测试结果。
根据《深入理解java虚拟机》代码示例,上面加有注释,
请在32位系统下运行
,可能也印证了64位下很难出现OOM。