JAVA内存报错解析

JAVA内存报错解析

1.   OutOfMemoeryError

出了程序计数器外,虚拟内存的其他几个区域(JAVA虚拟机栈、本地方法栈、JAVA堆、方法区,运行时常量池《方法区的一部分》、直接内存)都有可能产生这个错误。

 

1.1 JAVA虚拟机栈/本地方法栈

栈容量由-xss控制

/**

 * -Xss2M

 * @author Administrator

 *

 */

public classJavaVMStackVM {

   

    private void dontStop()

    {

        while(true)

        {

            try {

                Thread.sleep(1000);

            }catch(InterruptedExceptione) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

    }

   

    public void stackLeakByThread()

    {

        while(true)

        {

            Threadthread= newThread(newRunnable() {

               

                @Override

                publicvoid run() {

                    // TODO Auto-generated method stub

                    dontStop();

                }

            });

            thread.start();

        }

    }

   

    public static void main(String args[])

    {

        JavaVMStackVMoom= newJavaVMStackVM();

        oom.stackLeakByThread();

    }

 

}

 

运行后的报错如下:

 

1.2 JAVA堆

-Xms JAVA堆内存初始分配内存大小

-Xmx JAVA堆内存可分配内存的最大上限

-XX:+HeapDumpOnOutOfMemoryError

-XX:newSize:表示新生代初始内存的大小,应该小于-Xms的值例如-XX:newSize=20m

-XX:MaxnewSize:表示新生代可被分配的内存的最大上限;当然这个值应该小于 -Xmx的值;

-Xmn:至于这个参数则是对-XX:newSize、-XX:MaxnewSize两个参数的同时配置,也就是说如果通过-Xmn来配置新生代的内存大小

 

import java.util.ArrayList;

import java.util.List;

 

/**

 * -Xms10m-Xmx10m -XX:+HeapDumpOnOutOfMemoryError

 * @author Administrator

 *

 */

public classHeapOOM {

   

    public static void main(String args[])

    {

        List<String>list= newArrayList<String>();

        while(true)

        {

            list.add("123");

        }

    }

 

}

 

设置举例(选自http://unixboy.iteye.com/blog/174173/

·        java -Xmx3550m-Xms3550m -Xmn2g -Xss128k
-Xmx3550m
:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

·        java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m-XX:MaxTenuringThreshold=0
-XX:NewRatio=4
:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

 

不过从个人来看,具体取值要按照实际调优来决定。

1.3 方法区/运行时常量池

import java.util.ArrayList;

import java.util.List;

 

/**

 * -XX:PermSize=10M-XX:MaxPermSize=10M

 * @author Administrator

 *

 */

public classRuntimeConstantPoolOOM {

 

    public static void main(String[] args) {

        // TODO Auto-generated method stub

 

        List<String>list= newArrayList<>();

        int i = 0;

        while(true)

        {

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

        }

       

    }

 

}

 

Jdk8中已经没有永久代的说法,因此这两个参数不会在生效,hotspot中新增了元数据具体可参考http://www.importnew.com/14933.html

 

 在JDK8中设置元数据参数报错如下

import java.lang.reflect.Method;

 

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

/**

 * -XX:MetaspaceSize=2m-XX:MaxMetaspaceSize=2m JDK8

 * -XX:PermSize=10m-XX:MaxPermSize=10m JDK7

 * @author Administrator

 *

 */

public classJavaMethodAreaOOM {

   

    public static void main(String args[])

    {

        while(true)

        {

            Enhancerenhancer= newEnhancer();

            enhancer.setSuperclass(OOMObkect.class);

            enhancer.setUseCache(false);

            enhancer.setCallback(new MethodInterceptor() {

               

                @Override

                public Object intercept(Objectarg0,Methodarg1,Object[] arg2,MethodProxyarg3)throwsThrowable {

                    // TODO Auto-generated method stub

                    returnarg3.invoke(arg0,arg2);

                }

            });

            enhancer.create();

        }

    }

   

    static class OOMObkect

    {

       

    }

 

}

1.4  直接内存报错

import java.lang.reflect.Field;

 

import sun.misc.Unsafe;

 

/**

 * -Xms10m-Xmx10m -XX:MaxDirectMemorySize=10m

 * @author Administrator

 *

 */

public classDirectoryMemoryOOM {

   

    private static final long _1MB = 1024 * 1024;

    public static void main(String args[]) throws Exception

    {

        Fieldunsafe= Unsafe.class.getDeclaredFields()[0];

        unsafe.setAccessible(true);

        Unsafeun = (Unsafe) unsafe.get(null);

        while(true)

        {

            un.allocateMemory(_1MB);

        }

    }

 

}


 

Unsafe类的操作可阅读:http://www.cnblogs.com/mickole/articles/3757278.html

DirectMemory的http://w作用可参考这个wiki:ww.cnblogs.com/lyftest/p/6564547.html

2.   StackOverflowError

2.1虚拟机栈

 

/**

 * -Xss128K

 * @author Administrator

 *

 */

public classJavaVMStackError {

   

    private int stackLenth = 1;

   

    public void stackLeak()

    {

        this.stackLenth ++;

        stackLeak();

    }

 

    public static void main(String[] args) {

        // TODO Auto-generated method stub

       

        JavaVMStackErrorstatck=newJavaVMStackError();

        try

        {

            statck.stackLeak();

        }

        catch(Exceptione)

        {

            System.out.println(statck.stackLenth);

            //e.printStackTrace();

        }

 

    }

 

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值