栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

实战:OutOfMemoryError异常之 虚拟机栈和本地方法栈溢出

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

实战:OutOfMemoryError异常之 虚拟机栈和本地方法栈溢出

虚拟机参数
  • 虚拟机栈:-Xss128k,表示虚拟机栈最大内存为128k。
  • 本地方法栈:-Xoss128k,表示本地方法栈最大内存为128k。

        由于在HotSpot虚拟机中不区分虚拟机栈和本地方法栈,所以栈容量只由-Xss参数设定。

Java虚拟机规范中描述的两种异常
  • 如果线程请求栈深度大于虚拟机所允许最大深度(没有内存供继续分配),将抛出StackOverflowError异常。
  • 如果虚拟机在扩展栈时无法申请到足够内存,将抛出OutOfMemoryError异常。
单线程SOF测试 概述

        虚拟机栈由栈帧构成,每调用一次方法,将需要在虚拟机栈占用一块内存用于创建一个栈帧,当达到容量上限时,将不能创建栈帧,所以再次调用方法时会抛出异常。

代码清单
public class JavaVMStackSOF {

    private int stackLength = 1;

    public void stackLeak(){
        stackLength++;
        stackLeak(); // 迭代调用方法,创建栈帧,占用虚拟机栈的内存
    }

    public static void main(String[] args) throws Throwable{
        JavaVMStackSOF sof = new JavaVMStackSOF();
        try{
            sof.stackLeak();
        }catch (Throwable e){
            System.out.println("stack length: " + sof.stackLength);
            throw e;
        }
    }

}
VM Options参数设置

 运行结果

循环创建线程导致OOM异常 概述 

        在单线程程序中,无法出现OOM异常;但是通过循环创建线程(线程体调用方法),的放肆可以产生OOM异常。此时OOM异常产生的原因与栈空间是否足够大无关。

        出现OOM的原因是,操作系统分配给每个虚拟机进程的内存是有限制的,比如32位Windows限制为2GB,除去所有线程共享的堆内存和方法区,每开辟一个线程,都需要为其分配一定的栈内存和程序计数器(比重很小)。所以当线程数目达到一定数量时,内存耗尽,此时再有新线程启动时,会抛出OOM异常,因为没有内存分配给它。至于栈空间的容量设置影响到的是开辟的线程数量,栈空间容量越大,能够开辟的线程个数就越少。

代码清单
public class JavaVMStackOOM {
    private void dontStop(){
        while (true){

        }
    }

    // 循环创建线程,直到内存耗尽,抛出OOM异常
    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 oom = new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}
VM Options参数设置
VM Options:-Xss2M // 设置大一些,每个线程需要的内存多,能够创建的线程数量少
运行结果

        运行结果已清晰提示:无法继续创建线程        

Exception in Thread "main" java.lang.OutOfMemoryError: unable to create new native thread
总结
  • 如果使用虚拟机默认参数,栈深度到达1000~2000完全没问题。大多数情况下,对于方法的正常调用,包括递归,这个深度都够用。
  • 如果是建立多线程导致的内存溢出,而且不能减少线程数或者更换为64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346330.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号