首页 > 代码库 > jvm中除了程序计数器其他运行时区域的OutOfMemoryError

jvm中除了程序计数器其他运行时区域的OutOfMemoryError

技术分享

1. java堆溢出测试

java堆用于存储对象实例,只要不断创建对象,并且保证GC Roots到对象之间的可达路径来避免垃圾回收机制清理这些对象,那么当对象的达到堆的容量最大值滞后就会产生outofmemoryerror;

通过参数:-Xms20m 最小堆大小; -Xmx20m 最大堆大小;  -XX:+HeapDumpOnOutOfMemoryError  虚拟机在内存溢出异常时Dump出当前的内存堆转储快照

具体配置:

-verbose:gc -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:SurvivorRatio=8

代码:

技术分享
 1 package javaTest;
 2 
 3 import java.io.Serializable;
 4 import java.util.LinkedList;
 5 import java.util.List;
 6 
 7 public class Portal {
 8 
 9     /**
10      * vm args : -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
11      * @param args
12      */
13     public static void main(String[] args) {
14         System.out.println("test heap memory dump");
15         
16         
17         List<HeapOOM> lists = new LinkedList<HeapOOM>();
18         
19         while(true){
20             lists.add(new HeapOOM());
21         }
22         
23         
24         
25     }
26     
27     public static class HeapOOM implements Serializable{
28         
29         /**
30          * 
31          */
32         private static final long serialVersionUID = -7562967142125991489L;
33         
34         private int count;
35 
36         public int getCount() {
37             return count;
38         }
39 
40         public void setCount(int count) {
41             this.count = count;
42         }
43         
44         
45     }
46 
47 }
View Code

异常:

技术分享

注意:一定要辨别是内存泄露(memory Leak)还是内存溢出(memory Overflow)

2. java虚拟机栈和本地方法栈溢出

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverFlowError异常;

如果虚拟机的扩展栈无法申请到足够的内存空间,则抛出OutOfMemoryError异常;

参数:-Xoss 设置本地方法栈大小;-Xss 设置虚拟机房发展大小

具体设置:

-Xss128k

代码:

技术分享
 1 package javaTest;
 2 
 3 public class StackOverFlowTest {
 4     
 5     /**
 6      * vm args : -Xss128K
 7      * @param args
 8      */
 9     public static void main(String[] args){
10         
11         OverFlowStackClass model = new OverFlowStackClass();
12         
13         try{
14             model.stackLeak();
15         }catch(Throwable ex){
16             System.out.println("最大深度:"+String.valueOf(model.stackLength));
17             throw ex;
18         }
19         
20         
21         
22         
23         
24         
25     }
26     
27     static class OverFlowStackClass{
28         public int stackLength=1;
29         
30         public void stackLeak(){
31             stackLength++;
32             stackLeak();
33         }
34     }
35     
36     
37 
38 }
View Code

异常:

技术分享

如果是创建过多的线程导致内存溢出,在不减少线程数量或者更换64bit虚拟机的情况下,就只能通过减少最大堆和减少虚拟机栈容量来换取更多的线程,如果没有这方便的处理经验,这种通过增加线程挤占java虚拟机栈的方式来验证java栈的内存溢出(outofmemoryerror)的场景是很难想到的;

本人电脑是windows这里对于这种情况就不做演示了,代码实现其实就是疯狂的创建新的线程来实现。java栈的内存溢出;

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

String.intern();是一个Native方法,它的作用是 如果字符串常量池中已经包含一个等于此String对象的字符串,则返回字符串常量池中的这个字符串;否则创建一个新的对象,该对象添加到常量池中,最后返回此字符串的引用。

参数:-XX:PermSize  -XX:MaxPermSize

具体参数:

-XX:PermSize=10M -XX:MaxPermSize=10M

代码:

技术分享
 1 package javaTest;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 public class MethodOutOfMemoryError {
 7     
 8     /** 
 9      * vm args: -XX:PermSize=10M -XX:MaxPermSize=10M
10      * @param args
11      */
12     public static void main(String[] args){
13         
14         List<String> lists = new ArrayList<String>();
15         
16         int i=0;
17         while(true){
18             lists.add(String.valueOf(i++).intern());
19         }
20         
21     }
22 
23 }
View Code

异常:

1.7+以上版本不会出现异常了,可以通过:-verbose:gc查看GC的回收过程;

4. 本机直接内存溢出

参数:-XX:MaxDirectMemorySize 制定可以使用的机器内存的大小

具体运行参数:

-Xmx10m -XX:MaxDirectMemorySize=10m

代码:

技术分享
 1 package javaTest;
 2 
 3 import java.lang.annotation.Annotation;
 4 import java.lang.reflect.Field;
 5 
 6 import sun.misc.Unsafe;
 7 
 8 public class DirectMemoryTest {
 9 
10     private static final int _1MB = 1024*1024;
11     
12     /**
13      * vm agrs: -Xmx10m -XX:MaxDirectMemorySize=10m
14      * @param args
15      * @throws IllegalAccessException 
16      * @throws IllegalArgumentException 
17      */
18     public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException{
19         
20         System.out.println(_1MB);
21         
22         Field unsafeField = Unsafe.class.getDeclaredFields()[0];
23         unsafeField.setAccessible(true);
24         Unsafe unsafe = (Unsafe)unsafeField.get(null);
25         while(true){
26             unsafe.allocateMemory(_1MB);
27         }
28         
29         
30         
31         
32     }
33 }
View Code

异常:

技术分享

虽然java有垃圾回收机制,但是内存溢出对我们来说也是家常便饭,所以要明白什么情况下导致内存溢出,从而尽量避免内存溢出的发生;

 如果出现内存异常根据堆栈信息可以快速排查是什么原因;

 

 技术分享

 

jvm中除了程序计数器其他运行时区域的OutOfMemoryError