虚拟机栈和本地方法栈溢出

来源:互联网 发布:从淘宝怎么买东西便宜 编辑:程序博客网 时间:2024/05/18 18:21

1.概述

HotSpot虚拟机直接把虚拟机栈和本地方法栈合二为一,因此对于HotSpot来说,虽然-Xoss参数(设置本地方法栈大小)存在,但实际上是无效的,栈容量只由-Xss参数设定

2.StackOverflowError

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常

package com.java.one;/** * 栈深度大于虚拟机所允许最大深度导致StackOverflowErroe * 以单线程为例 * VM Args: -Xss128K(-Xss虚拟机栈) * */public class JavaVMStackSOF {    private int stackLength = 1;    public void stackLeak () {        stackLength++;        stackLeak();    }    public static void main(String[] args) {        JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();        try {            javaVMStackSOF.stackLeak();        } finally {            System.out.println("栈深度stackLength: " + javaVMStackSOF.stackLength);        }    }}

打印异常信息:

栈深度stackLength: 997Exception in thread "main" java.lang.StackOverflowError    at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)    at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)    at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)    at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)    at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)    at com.java.one.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)。。。

在单个线程下,无论是由于栈帧太大还是虚拟机栈容量太小(这里Xss为128K),当内存无法分配时,虚拟机抛出的都是StackOverflowError异常
运行结果

3.OutOfMemoryError

如果虚拟机在扩展时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
多线程下的内存溢出与栈空间是否足够大并不存在任何联系,换句话说,操作系统内存大小是有限制的,每个线程的栈分配的内存越大,可建立的线程数就越少,反而越容易产生内存溢出
操作系统分配内存=Xmx(堆最大容量)+MaxPermSize(方法区最大容量)+程序计数器消耗内存+虚拟机进程消耗内存+虚拟机栈和本地方法栈消耗内存

package com.java.one;/** * 创建线程导致内存溢出异常 * VM Args: -Xss2M(虚拟机栈容量Xss不妨设置大一些,可建立线程数就越少) * 操作系统分配内存=Xmx(堆最大容量)+MaxPermSize(方法区最大容量)+程序计数器消耗内存+虚拟机进程消耗内存+虚拟机栈(本地方法栈)消耗内存 * */public class JavaVMStackOOM {    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) {        JavaVMStackOOM javaVMStackOOM = new JavaVMStackOOM();        javaVMStackOOM.stackLeakByThread();    }}

建立多线程导致内存溢出,在不能减少线程或更换64位虚拟机的情况下,只能通过减少堆最大容量减少栈容量来换取更多的线程