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: 997
Exception 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位虚拟机的情况下,只能通过减少堆最大容量减少栈容量来换取更多的线程

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐