JVM学习之常见溢出类型

Java堆

所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:

 1 public class HeapOOM {
 2     
 3     static class OOMObject{}
 4 
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         List<OOMObject> list = new ArrayList<OOMObject>();
10         
11         while(true){
12             list.add(new OOMObject());
13         }
14     }
15 
16 }

加上JVM参数-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快报出OOM:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

并且能自动生成Dump。

方法区)

    方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带:

 1 public class MethodAreaOOM {
 2     
 3     static class OOMOjbect{}
 4 
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         // TODO Auto-generated method stub
10         while(true){
11             Enhancer eh = new Enhancer();
12             eh.setSuperclass(OOMOjbect.class);
13             eh.setUseCache(false);
14             eh.setCallback(new MethodInterceptor(){
15 
16                 @Override
17                 public Object intercept(Object arg0, Method arg1,
18                         Object[] arg2, MethodProxy arg3) throws Throwable {
19                     // TODO Auto-generated method stub
20                     return arg3.invokeSuper(arg0, arg2);
21                 }
22                 
23             });
24             eh.create();
25         }
26     }
27 
28 }

加上永久带的JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

静态变量或常量也会有可能撑爆方法区:

 1 public class ConstantOOM {
 2 
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) {
 7         // TODO Auto-generated method stub
 8         List<String> list = new ArrayList<String>();
 9         int i=0;
10         while(true){
11             list.add(String.valueOf(i++).intern());
12         }
13     }
14 
15 }

同样加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后报如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

3)Java栈和本地方法栈

    栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,栈大小由Xss来调节,方法调用层次太多会撑爆这个区域,samples如下所示:

 1 package com.cutesource;
 2 
 3 public class StackOOM {
 4 
 5     /**
 6      * @param args
 7      */
 8     
 9     private int stackLength = 1;
10     
11     public void stackLeak(){
12         stackLength++;
13         stackLeak();
14     }
15     
16     public static void main(String[] args) throws Throwable{
17         // TODO Auto-generated method stub
18         StackOOM oom = new StackOOM();
19         try{
20             oom.stackLeak();
21         }catch(Throwable err){
22             System.out.println("Stack length:" + oom.stackLength);
23             throw err;
24         }
25         
26     }
27 
28 }

设置JVM参数:-Xss128k,报出异常:

Exception in thread "main" java.lang.StackOverflowError

打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:

 1 package com.cutesource;
 2 
 3 public class StackOOM {
 4 
 5     /**
 6      * @param args
 7      */
 8     
 9     private int stackLength = 1;
10     
11     private void dontStop(){
12         while(true){
13             try{Thread.sleep(1000);}catch(Exception err){}
14         }
15     }
16     
17     public void stackLeakByThread(){
18         while(true){
19             Thread t = new Thread(new Runnable(){
20 
21                 @Override
22                 public void run() {
23                     // TODO Auto-generated method stub
24                     dontStop();
25                 }
26                 
27             });
28             t.start();
29             stackLength++;
30         }
31     }
32     
33     public static void main(String[] args) throws Throwable{
34         // TODO Auto-generated method stub
35         StackOOM oom = new StackOOM();
36         try{
37             oom.stackLeakByThread();
38         }catch(Throwable err){
39             System.out.println("Stack length:" + oom.stackLength);
40             throw err;
41         }
42         
43     }
44 
45 }

报出异常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread

不过在windows上运行这个例子要小心,会出现系统假死的情况,有可能需要重启机器才行。

以上几个例子虽然比较简单,但能很好帮助普通的程序员更加直观的了解Java堆方法区Java栈和本地方法栈

原文地址:https://www.cnblogs.com/sunfie/p/5124752.html