您的位置:首页 > 编程语言 > Java开发

从几个sample来学习Java堆,方法区,Java栈和本地方法栈

2015-12-10 10:22 826 查看
最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构:



感觉有必要通过几个实在的例子来加深对这几个区域的了解

1)Java堆

所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:

[java] view
plaincopy

public class HeapOOM {  

      

    static class OOMObject{}  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        List<OOMObject> list = new ArrayList<OOMObject>();  

          

        while(true){  

            list.add(new OOMObject());  

        }  

    }  

  

}  

加上JVM参数-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快报出OOM:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

并且能自动生成Dump。

2)方法区

方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带:

[java] view
plaincopy

public class MethodAreaOOM {  

      

    static class OOMOjbect{}  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        // TODO Auto-generated method stub  

        while(true){  

            Enhancer eh = new Enhancer();  

            eh.setSuperclass(OOMOjbect.class);  

            eh.setUseCache(false);  

            eh.setCallback(new MethodInterceptor(){  

  

                @Override  

                public Object intercept(Object arg0, Method arg1,  

                        Object[] arg2, MethodProxy arg3) throws Throwable {  

                    // TODO Auto-generated method stub  

                    return arg3.invokeSuper(arg0, arg2);  

                }  

                  

            });  

            eh.create();  

        }  

    }  

  

}  

加上永久带的JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

静态变量或常量也会有可能撑爆方法区:

[java] view
plaincopy

public class ConstantOOM {  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        // TODO Auto-generated method stub  

        List<String> list = new ArrayList<String>();  

        int i=0;  

        while(true){  

            list.add(String.valueOf(i++).intern());  

        }  

    }  

  

}  

同样加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后报如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

3)Java栈和本地方法栈

栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,栈大小由Xss来调节,方法调用层次太多会撑爆这个区域,samples如下所示:

[java] view
plaincopy

package com.cutesource;  

  

public class StackOOM {  

  

    /** 

     * @param args 

     */  

      

    private int stackLength = 1;  

      

    public void stackLeak(){  

        stackLength++;  

        stackLeak();  

    }  

      

    public static void main(String[] args) throws Throwable{  

        // TODO Auto-generated method stub  

        StackOOM oom = new StackOOM();  

        try{  

            oom.stackLeak();  

        }catch(Throwable err){  

            System.out.println("Stack length:" + oom.stackLength);  

            throw err;  

        }  

          

    }  

  

}  

设置JVM参数:-Xss128k,报出异常:

Exception in thread "main" java.lang.StackOverflowError

打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:

[java] view
plaincopy

package com.cutesource;  

  

public class StackOOM {  

  

    /** 

     * @param args 

     */  

      

    private int stackLength = 1;  

      

    private void dontStop(){  

        while(true){  

            try{Thread.sleep(1000);}catch(Exception err){}  

        }  

    }  

      

    public void stackLeakByThread(){  

        while(true){  

            Thread t = new Thread(new Runnable(){  

  

                @Override  

                public void run() {  

                    // TODO Auto-generated method stub  

                    dontStop();  

                }  

                  

            });  

            t.start();  

            stackLength++;  

        }  

    }  

      

    public static void main(String[] args) throws Throwable{  

        // TODO Auto-generated method stub  

        StackOOM oom = new StackOOM();  

        try{  

            oom.stackLeakByThread();  

        }catch(Throwable err){  

            System.out.println("Stack length:" + oom.stackLength);  

            throw err;  

        }  

          

    }  

  

}  

报出异常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread

不过在windows上运行这个例子要小心,会出现系统假死的情况,有可能需要重启机器才行。

以上几个例子虽然比较简单,但能很好帮助普通的程序员更加直观的了解Java堆方法区Java栈和本地方法栈

转自:http://blog.csdn.net/cutesource/article/details/8244250
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: