【深入Java虚拟机】之三:内存溢出

为了更直接的了解各区域,下面我们来看几个示例。

1、Java 堆溢出

下面的程中我们限制Java 堆的大小为20MB,不可扩展(将堆的最小值-Xms 参

数与最大值-Xmx 参数设置为一样即可避免堆自动扩展),通过参数-XX:+HeapDump

OnOutOfMemoryError 可以让虚拟机在出现内存溢出异常时Dump 出当前的内存堆转储

快照以便事后进行分析。

参数设置如下



 



 


 Java 堆内存的OutOfMemoryError异常是实际应用中最常见的内存溢出异常情况。出现Java 堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。要解决这个区域的异常,一般的手段是首先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump 出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。图2-5 显示了使用Eclipse Memory Analyzer 打开的堆转储快照文件。

如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots 的引用链。于是就能找到泄漏对象是通过怎样的路径与GC Roots 相关联并导致垃圾收集器无法自动回收

它们的。掌握了泄漏对象的类型信息,以及GC Roots 引用链的信息,就可以比较准确地定位出泄漏代码的位置。

如果不存在泄漏,换句话说就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx 与-Xms),与机器物理内存对比看是否还可以调大,从代码上

检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

以上是处理Java 堆内存问题的简略思路,处理这些问题所需要的知识、工具与经验在后面的几次分享中我会做一些额外的分析。

 

2、java栈溢出 

Java代码  收藏代码
  1. package com.yhj.jvm.memory.stack;  
  2. /** 
  3.  * @Described:栈层级不足探究 
  4.  * @VM args:-Xss128k 
  5.  * @author YHJ create at 2011-11-12 下午08:19:28 
  6.  * @FileNmae com.yhj.jvm.memory.stack.StackOverFlow.java 
  7.  */  
  8. public class StackOverFlow {  
  9.     private int i ;  
  10.     public void plus() {  
  11.        i++;  
  12.        plus();  
  13.     }  
  14.     /** 
  15.      * @param args 
  16.      * @Author YHJ create at 2011-11-12 下午08:19:21 
  17.      */  
  18.     public static void main(String[] args) {  
  19.        StackOverFlow stackOverFlow = new StackOverFlow();  
  20.        try {  
  21.            stackOverFlow.plus();  
  22.        } catch (Exception e) {  
  23.            System.out.println("Exception:stack length:"+stackOverFlow.i);  
  24.            e.printStackTrace();  
  25.        } catch (Error e) {  
  26.            System.out.println("Error:stack length:"+stackOverFlow.i);  
  27.            e.printStackTrace();  
  28.        }  
  29.     }  
  30. }   

3、 方法区溢出 

Java代码  收藏代码
  1. package com.yhj.jvm.memory.methodArea;  
  2. import java.lang.reflect.Method;  
  3. import net.sf.cglib.proxy.Enhancer;  
  4. import net.sf.cglib.proxy.MethodInterceptor;  
  5. import net.sf.cglib.proxy.MethodProxy;  
  6. /** 
  7.  * @Described:方法区溢出测试 
  8.  * 使用技术 CBlib 
  9.  * @VM args : -XX:PermSize=10M -XX:MaxPermSize=10M 
  10.  * @author YHJ create at 2011-11-12 下午08:47:55 
  11.  * @FileNmae com.yhj.jvm.memory.methodArea.MethodAreaOutOfMemory.java 
  12.  */  
  13. public class MethodAreaOutOfMemory {  
  14.     /** 
  15.      * @param args 
  16.      * @Author YHJ create at 2011-11-12 下午08:47:51 
  17.      */  
  18.     public static void main(String[] args) {  
  19.        while(true){  
  20.            Enhancer enhancer = new Enhancer();  
  21.            enhancer.setSuperclass(TestCase.class);  
  22.            enhancer.setUseCache(false);  
  23.            enhancer.setCallback(new MethodInterceptor() {  
  24.               @Override  
  25.               public Object intercept(Object arg0, Method arg1, Object[] arg2,  
  26.                      MethodProxy arg3) throws Throwable {  
  27.                   return arg3.invokeSuper(arg0, arg2);  
  28.               }  
  29.            });  
  30.            enhancer.create();  
  31.        }  
  32.     }  
  33. }  
  34. /** 
  35.  * @Described:测试用例 
  36.  * @author YHJ create at 2011-11-12 下午08:53:09 
  37.  * @FileNmae com.yhj.jvm.memory.methodArea.MethodAreaOutOfMemory.java 
  38.  */  
  39. class TestCase{  
  40.      
  41. }  
 
4、常量池溢出(常量池都有哪些信息,我们在后续的JVM类文件结构中详细描述) 
Java代码  收藏代码
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. /** 
  4.  * @Described:常量池内存溢出探究 
  5.  * @VM args : -XX:PermSize=10M -XX:MaxPermSize=10M 
  6.  * @author YHJ create at 2011-10-30 下午04:28:30 
  7.  * @FileNmae com.yhj.jvm.memory.constant.ConstantOutOfMemory.java 
  8.  */  
  9. public class ConstantOutOfMemory {  
  10.     /** 
  11.      * @param args 
  12.      * @throws Exception 
  13.      * @Author YHJ create at 2011-10-30 下午04:28:25 
  14.      */  
  15.     public static void main(String[] args) throws Exception {  
  16.        try {  
  17.            List<String> strings = new ArrayList<String>();  
  18.            int i = 0;  
  19.            while(true){  
  20.               strings.add(String.valueOf(i++).intern());  
  21.            }  
  22.        } catch (Exception e) {  
  23.            e.printStackTrace();  
  24.            throw e;  
  25.        }  
  26.     }  

5、直接内存溢出 

Java代码  收藏代码
  1. package com.yhj.jvm.memory.directoryMemory;  
  2. import java.lang.reflect.Field;  
  3. import sun.misc.Unsafe;  
  4. /** 
  5.  * @Described:直接内存溢出测试 
  6.  * @VM args: -Xmx20M -XX:MaxDirectMemorySize=10M 
  7.  * @author YHJ create at 2011-11-12 下午09:06:10 
  8.  * @FileNmae com.yhj.jvm.memory.directoryMemory.DirectoryMemoryOutOfmemory.java 
  9.  */  
  10. public class DirectoryMemoryOutOfmemory {  
  11.    
  12.     private static final int ONE_MB = 1024*1024;  
  13.     private static int count = 1;  
  14.    
  15.     /** 
  16.      * @param args 
  17.      * @Author YHJ create at 2011-11-12 下午09:05:54 
  18.      */  
  19.     public static void main(String[] args) {  
  20.        try {  
  21.            Field field = Unsafe.class.getDeclaredField("theUnsafe");  
  22.            field.setAccessible(true);  
  23.            Unsafe unsafe = (Unsafe) field.get(null);  
  24.            while (true) {  
  25.               unsafe.allocateMemory(ONE_MB);  
  26.               count++;  
  27.            }  
  28.        } catch (Exception e) {  
  29.            System.out.println("Exception:instance created "+count);  
  30.            e.printStackTrace();  
  31.        } catch (Error e) {  
  32.            System.out.println("Error:instance created "+count);  
  33.            e.printStackTrace();  
  34.        }  
  35.    
  36.     }  
  37.    
  38. }  
posted @ 2019-02-20 15:57  tiger168  阅读(153)  评论(0编辑  收藏  举报