JVM学习笔记-内存溢出

在实际编程过程中,会遇到一些OutOfMemory(OOM)异常。通过模拟。我们可以直接指出这些场景的本质,从而在纷繁复杂的千万行代码中避免这样去Coding。导致OOM的情况有多种,包括Java或Native Method Stack的内存不足或者栈空间溢出、Heap内存溢出、Non-heap内存溢出、Direct Memory溢出。

  1. Java Method Stack栈溢出模拟
什么时候会让Java Method Stack栈溢出?栈的基本特点就是FILO(First In Last Out),如果in的太多而out的太少,就可能overflow了。而Java Method Statck的功能就是保存每一次函数调用时的“现场”,即为入栈,函数返回对应出栈,所以函数的调用深度越大,栈就变得越大,足够大的时候就会溢出。所以模拟Java Method Stack溢出,只要不断递归调用某一函数就可以导致溢出。
  1. package com.jony.java; 
  2.  
  3. public class TestStackOverflow { 
  4.     private int stackLength = 0
  5.  
  6.     public void stackOverFlow(){ 
  7.         ++stackLength; 
  8.         stackOverFlow(); 
  9.     } 
  10.  
  11.     public static void main(String[] args){ 
  12.         TestStackOverflow test = new TestStackOverflow(); 
  13.         try
  14.             test.stackOverFlow(); 
  15.         } catch (Throwable e) { 
  16.             System.out.println("Stack Length:" + test.stackLength); 
  17.             e.printStackTrace(); 
  18.         } 
  19.     } 
  20.  
package com.jony.java;

public class TestStackOverflow {
    private int stackLength = 0;

    public void stackOverFlow(){
        ++stackLength;
        stackOverFlow();
    }

    public static void main(String[] args){
        TestStackOverflow test = new TestStackOverflow();
        try {
            test.stackOverFlow();
        } catch (Throwable e) {
            System.out.println("Stack Length:" + test.stackLength);
            e.printStackTrace();
        }
    }

}
运行结果:
Stack Length:11477
java.lang.StackOverflowError
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:7)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)
at com.jony.java.TestStackOverflow.stackOverFlow(TestStackOverflow.java:8)

        2.  Java Method Stack内存溢出模拟-Heap内存溢出
堆是用来存储对象的,当然对象不一定都存在堆里(栈上分配、标量替换技术)。那么堆如果溢出了,一定是不能被杀掉的对象太多了。模拟Heap内存溢出,只要不断的创建对象并保存对象引用存在即可。
  1. package com.jony.java; 
  2.  
  3. import java.util.ArrayList; 
  4.  
  5. public class TestHeapOverflow { 
  6.  
  7.     static class TestOomHeap {} 
  8.  
  9.     public static void main(String[] args) { 
  10.         ArrayList<TestOomHeap> list = new ArrayList<TestHeapOverflow.TestOomHeap>(); 
  11.  
  12.         while (true) { 
  13.             list.add(new TestOomHeap()); 
  14.         } 
  15.     } 
  16.  
package com.jony.java;

import java.util.ArrayList;

public class TestHeapOverflow {

    static class TestOomHeap {}

    public static void main(String[] args) {
        ArrayList<TestOomHeap> list = new ArrayList<TestHeapOverflow.TestOomHeap>();

        while (true) {
            list.add(new TestOomHeap());
        }
    }

}
运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.jony.java.TestHeapOverflow.main(TestHeapOverflow.java:13)


       3.  Method Area内存溢出
Method Area内存溢出,也就是Non-heap,是用来存储Object Class Data、变量、静态常量、JIT编译后的代码。如果该区域溢出,则说明某种数据创建的实在是太多了,模拟该异常,可以不断创建新的class,知道溢出为止。下面实例中会用到asm-all-3.0.jar和cglib2.2.jar 下载
  1. package com.jony.java; 
  2.  
  3. import java.lang.reflect.Method; 
  4. import net.sf.cglib.proxy.Enhancer; 
  5. import net.sf.cglib.proxy.MethodInterceptor; 
  6. import net.sf.cglib.proxy.MethodProxy; 
  7.  
  8. public class TestMethodAreaOverflow { 
  9.  
  10.     static class MethodAreaOom {} 
  11.  
  12.     public static void main(String[] args) { 
  13.         while (true) { 
  14.             Enhancer enhancer = new Enhancer(); 
  15.             enhancer.setSuperclass(MethodAreaOom.class); 
  16.             enhancer.setUseCache(false); 
  17.             enhancer.setCallback(new MethodInterceptor() { 
  18.                  
  19.                 @Override 
  20.                 public Object intercept(Object arg0, Method arg1, Object[] arg2, 
  21.                         MethodProxy proxy) throws Throwable { 
  22.                     return proxy.invoke(arg0, arg2); 
  23.                 } 
  24.             }); 
  25.             enhancer.create(); 
  26.         } 
  27.     } 
  28.  
package com.jony.java;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TestMethodAreaOverflow {

    static class MethodAreaOom {}

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MethodAreaOom.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                
                @Override
                public Object intercept(Object arg0, Method arg1, Object[] arg2,
                        MethodProxy proxy) throws Throwable {
                    return proxy.invoke(arg0, arg2);
                }
            });
            enhancer.create();
        }
    }

}
运行结果:
Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at com.jony.java.TestMethodAreaOverflow.main(TestMethodAreaOverflow.java:26)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
... 3 more
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
... 8 more

4.Runtime Constant Pool In Method  Area溢出
在运行时产生大量常量就可以让Method Area溢出,运行时常量可以用String类的intern方法,不断产生新的常量。
  1. package com.jony.java; 
  2.  
  3. import java.util.ArrayList; 
  4.  
  5. public class RCPverflow { 
  6.  
  7.     public static void main(String[] args) { 
  8.         ArrayList<String> list = new ArrayList<String>(); 
  9.         int i = 0
  10.         while (true) { 
  11.             list.add(String.valueOf(i++).intern()); 
  12.         } 
  13.     } 
  14.  
package com.jony.java;

import java.util.ArrayList;

public class RCPverflow {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        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.jony.java.RCPverflow.main(RCPverflow.java:11)


总结
在实际编程中要尽量避免此类错误,不过大多数程序设计的结构要比实例复杂很多,使得问题被应藏,但JVM内存溢出问题本质上就是以上几种问题,因此在实际编程中应该避免JVM内存溢出情况。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值