JVM内存溢出(OutOfMemoryError异常)

  1.  Java堆java

    java堆用于存储对象实例,只要不断的建立对象,而且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么当对象数量达到最大堆容量限制后就会产生OutOfMemoryError异常。当出现java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space,以下:多线程

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2760)
        at java.util.Arrays.copyOf(Arrays.java:2734)
        at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
        at java.util.ArrayList.add(ArrayList.java:351)
        at com.test.outofmemory.HeapOOM.main(HeapOOM.java:25)框架

     

    解决方式:jvm

        设置Eclipse的jvm参数:测试

-Xms256M -Xmx512M -XX:PermSize=256m -XX:MaxPermSize=512mspa


 

    2.Java虚拟机栈和本地方法栈溢出操作系统

 

    关于java虚拟机栈和本地方法栈,在java虚拟机中描述了两种异常:线程

  • 若是线程请求的栈深度大于虚拟机容许的最大深度,将抛出StackOverflowError异常代理

  • 若是虚拟机在扩展栈时没法申请到足够的内存空间,则抛出OutOfMemoryError异常(OutOfMemoryError unable to cteate new native thread)。code

    解决方式:

     

     

    -Xss:设置每条线程的Statck大小.在JDK1.5之后默认是1M,以前是256K

    抛出StackOverFlow异常:操做系统分配给每一个线程的内存是有限的,机器总内存减去Xmx再减去MaxPermSize,程序计数器占内存不多忽略,剩下的内存被虚拟机栈和本地方法栈瓜分,每一个线程分到的栈容量越大,分配的线程数就小。正常状况栈深度1000-2000没问题,若是是创建更多线程致使的内存溢出,在不能减小线程的状况下,只能经过减少Xmx和栈容量来换取更多线程。

 

    3.方法区和运行时常量池溢出

 

        若是要向运行时常量池中添加内容,最简单的作法就是使用String.intern()这个Native方法。该方法的做用是:若是池中已经包含一 个等于此String对象的字符串,则返回表明池中这个字符串的String对象;不然,将此String对象包含的字符串添加到常量池中,而且返回此 String对象的引用。因为常量池分配在方法区内,咱们能够经过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接 限制其中常量池的容量,如代码所示,运行时常量池致使的内存溢出异常。

/**  * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M * @author zzm  */ 
 public class RuntimeConstantPoolOOM {   
     public static void main(String[] args) {     
         // 使用List保持着常量池引用,避免Full GC回收常量池行为     
         List<String> list = new ArrayList<String>();      
         // 10MB的PermSize在integer范围内足够产生OOM了      
         int i = 0;      
         while (true) {          
             list.add(String.valueOf(i++).intern());      
         }  
     }  
}

    运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.String.intern(Native Method)
    at com.test.outofmemory.HeapOOM.main(HeapOOM.java:34)

    从运行结果中能够看到,运行时常量池溢出,在OutOfMemoryError后面跟随的提示信息是“PermGen space”,说明运行时常量池属于方法区(HotSpot虚拟机中的永久代)的一部分。

    方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。对于这些区域的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出。

虽然直接使用Java SE API也能够动态产生类(如反射时的GeneratedConstructorAccessor和动态代理等),但在本次实验中操做起来比较麻烦。在代码清单2-8中,笔者借助CGLib直接操做字节码运行时生成了大量的动态类。

值得特别注意的是,咱们在这个例子中模拟的场景并不是纯粹是一个实验,这样的应用常常会出如今实际应用中:当前的不少主流框架,如Spring、 Hibernate,在对类进行加强时,都会使用到CGLib这类字节码技术,加强的类越多,就须要越大的方法区来保证动态生成的Class能够加载入内 存。另外,JVM上的动态语言(例如Groovy等)一般都会持续建立类来实现语言的动态性,随着这类语言的流行,也愈来愈容易遇到与代码清单2-8类似 的溢出场景。

代码清单2-8 借助CGLib使方法区出现内存溢出异常

/**
 * 
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 * 
 */

public class JavaMethodAreaOOM {
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object obj, Method method,
                        Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            enhancer.create();
        }
    }
    static class OOMObject {
    }
}

 

运行结果:

 

Caused by: java.lang.OutOfMemoryError: PermGen space  

at java.lang.ClassLoader.defineClass1(Native Method)  

at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)  

at java.lang.ClassLoader.defineClass(ClassLoader.java:616)  ... 8 more

方法区溢出也是一种常见的内存溢出异常,一个类要被垃圾收集器回收掉,断定条件是比较苛刻的。在常常动态生成大量Class的应用中,须要特别注意类的回 收情况。这类场景除了上面提到的程序使用了CGLib字节码加强和动态语言以外,常见的还有:大量JSP或动态产生JSP文件的应用(JSP第一次运行时 须要编译为Java类)、基于OSGi的应用(即便是同一个类文件,被不一样的加载器加载也会视为不一样的类)等。

 

解决方式:

-PermSize :方法区的初始容量,默认是物理内存的1/64

-MaxPermSize :最大方法区容量。

 

4.本地直接内存溢出

 

    并非虚拟机运行时数据区的一部分。JDK1.4中引入了NIO类,引入了一种基于通道与缓冲区的I/O方式,可使用Native直接分配堆外内存,避免了再Java堆和Native堆中来回复制数据。

不会受到Java堆内存限制,但会受到机器总内存的限制。

若是如法申请到足够的空间抛出OutOfMemoryError。

 

解决方式:-XX:MaxDirectMemorySize 本机直接内存大小,若是不指定,则与Xmx同样。

相关文章
相关标签/搜索