栈内存溢出

2017-12-12  本文已影响0人  Richard_80ec

计算机中每个操作系统给每个进程的内存是有限制的(windows64位系统中最大分配内存是2G),即对于虚拟机,最大内存是2G,不算虚拟机进程启动时所占用的内存,剩下的内存分配给共享区和线程独享区,共享区的内存大小由虚拟机参数(-Xmx最大堆内存,MaxPermSize最大方法区容量)指定,剩下的则分配给栈空间,程序计数器占用的空间极小可忽略不计,每个线程分配到的栈容量越大,可以建立的线程的数量自然就越少,建立线程时则更容易将内存耗尽。
测试:

public class JavaVMStackSOF {

    private int stackLength = 1;

    public void stackLeak(){
        stackLength ++;
        stackLeak();
    }

    public static void main(String[] args) {
        JavaVMStackSOF oom = new JavaVMStackSOF();

        try {
            oom.stackLeak();
        }catch (Throwable e){
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }
}

设置虚拟机参数:
-Xss128k :设置每个线程的栈大小,减小这个值,可以使虚拟机创建更多线程
运行结果:

stack length:967
Exception in thread "main" java.lang.StackOverflowError
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:11)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
...

报出虚拟机栈超出虚拟机允许的最大深度的错误(StackOverflowError)。
通过-Xss控制了每个线程的最大栈大小,当栈不断增大时,会暴露栈空间不足的错误,这种错误有两种,一种是上述的栈深度超出,个人理解应该跟数组的outOfIndexError差不多的意思。
另一种就是虚拟机为栈分配的空间不足了,造成内存溢出。
代码:

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();
    }
}

设置虚拟机参数:
-Xss2m 将每个线程分配的空间调大一些
由于java线程是映射到操作系统的内核线程上的,因此上述代码执行有较大风险,可能会导致操作系统假死。本人测试的时候就死机了。。。

上一篇下一篇

猜你喜欢

热点阅读