JVM总结-内存溢出分析

在实际的开发中我们可能会遇到各种各样的内存溢出(OutOfMemoryError)问题,我在开发的时候就遇到过这样的情况。当时是报的这样异常

Caused by:java.lang.OutOfMemoryError:PermGen Space
  at java.lang.ClassLoader……
   
   
  • 1
  • 2
  • 1
  • 2

造成这个原因的是我们的tomcat下方了好几个web程序,而且每个程序都有大量的spring ,hibernate的jar包,并且这几个程序的jar基本上都是一样的。这就造成了重复加载的情况,直接导致我的永久区溢出。后来把公共的jar提出来放在一个share文件夹下,这样就可以了。而且Spring,Hibernate,在对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的class可以加载如内存。

java堆溢出 
java堆用于存储对象,所有不断的创建对象并且在GC Roots到对象之间有可达路径避免垃圾回收清除这些对象,在对象数量达到最大堆的容量限制后就会产生堆溢出

public class HeapOOM {

    static class OOMObject{}

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

    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

堆内存溢出

虚拟机栈和本地方法栈溢出 
栈容量的设置由参数-Xss参数设置。java虚拟机规范中描述的异常

  • 如果线程请求的栈深度大于虚拟机所运行的最大深度,将抛出StackOverflowError
  • 如果虚拟机在扩展时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
public class JavaVMStackOF {

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

    }

}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

栈溢出 
实验表明:在当个线程下,无论由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,虚拟机抛出的都是StackOverflowErroe异常 
方法区和运行时常量池溢出 
运行时 常量池是方法区的一部分。我们通过一个String.intern()方法来测试。String.intern()是一个本地方法,如果字符串常量池中已经包含一个等于此String对象,则返回代表池中这个字符串的String对象;否则将此String对象包含的字符串添加到常量池中,并且返回该String对象的引用。

public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        //使用list保持对常量池引用,避免Full GC回收常量池
        List<String> list=new ArrayList<String>();
        int i=0;
        while(true)
            list.add(String.valueOf(i++).intern());

    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

方法区溢出 
这里我一开始是用jre7的,结果没反应,改为jre6才有产生这样的情况。 
JVM上的动态语言通常会持续创建类来实现语言的动态性,也会经常造成PermGen space异常

直接内存溢出 
DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,默认与java堆的最大值-Xmx一样。

public class DirectMemoryOOM {

    private static final int _1MB=1024*1024;

    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        Field unsafeField=Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe=(Unsafe) unsafeField.get(null);
        while(true)
            unsafe.allocateMemory(_1MB);
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

直接内存溢出 
由DirectMemory导致的内存溢出,一个很明显的特征是在Heap Dump文件中不会看见明显的异常。如果发现OOM情况后Dump文件很小,而程序中又使用了NIO,可以检查是不是直接内存溢出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值