java虚拟机(二)java虚拟机的内存溢出异常

除了程序计数器,虚拟机中的其他几个运行时数据区都有发生内存溢出异常的可能。

Java堆内存溢出:

Java堆的作用是存储对象实例,因此也意味着只要不断的创建对象,并且避免被垃圾回收,就会出现Java堆溢出的异常。

首先在idea中设置JVM参数,在VM options中设置参数,具体步骤按如下:

以下为JVM中配置的参数信息,-verbose:gc 表示打开GC的跟踪日志;-Xms表示最小堆空间,-Xmx表示最大堆空间,-Xmn表示新生代的大小,-XX:+PrintGCTimeStamps表示打印GC发生的时间戳;-XX:SurvivorRatio=8表示新生代中Eden区域和Survivor区域的容量比值

-verbose:gc
-Xms20M
-Xmx20M
-Xmn10M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8

通过一段简单的java代码不断创建对象,当内存超过JVM设置的最大堆空间后就发生堆内存溢出:

public class JavaHeapOOM {
    static class  OOMproject{

    }
    public static void main(String[] args){
        List<OOMproject> list=new ArrayList<OOMproject>();
        while (true){
            list.add(new OOMproject());
        }
    }
}

程序执行后就会因为堆内存溢出而发生报错:

扫描二维码关注公众号,回复: 8503176 查看本文章

虚拟机栈和本地方法栈内存溢出:

虚拟机栈和本地方法栈用于存放局部变量表、操作栈、动态链接、方法出口等信息,因此可以使用类似递归的方式不断调用方法压入栈中(有数据结构基础的人应该很好理解),让线程请求的栈深度大于虚拟机所允许的最大深度

首先还是设置jvm参数,这里可以使用-Xss128k让虚拟机栈的内存变得很小,接着运行下面的代码:

public class JavaVMStackOF {
    private int stackLength=1;
    public void stackLeak(){
        stackLength++;
        stackLeak();
    }
    public static void main(String[] args)throws Throwable{
        JavaVMStackOF oom=new JavaVMStackOF();
        try{
            oom.stackLeak();
        }catch (Throwable e){
            System.out.println("stack length = " +oom.stackLength);
            throw e;
        }

    }
}

从结果中可以看出,在调用了991次stackleak()方法后,发生了StackOverFlowError

虚拟机栈和本地方法栈内存还有一种异常叫做OutOfMemoryError,要出现这个异常其实并不容易,其中一个思路就是不断创建线程,并且让每个线程都运行,接着便会发生OutOfMemoryError:

public class JVMStackOOM {
    private void dontstop(){
        while(true){}
    }
    public void stackLeakThread(){
        while(true){
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    dontstop();
                }
            });
            thread.start();
        }
    }
    public static void main(String[] args){
        JVMStackOOM oom=new JVMStackOOM();
        oom.stackLeakThread();
    }
}

上面的代码可能会导致操作系统假死,请谨慎执行!

方法区内存溢出:

方法区存放的是已经被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据,因此想让方法区溢出可以产生大量的类去填满方法区从而导致溢出。产生方法区内存溢出的原因还有大量JSP或动态产生JSP文件的应用等等。

发布了54 篇原创文章 · 获赞 604 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41973594/article/details/101383636