`

java 内存异常

 
阅读更多

转载 http://blog.csdn.net/cutesource/article/details/8244250

 

最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构:

感觉有必要通过几个实在的例子来加深对这几个区域的了解

1)Java堆

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

 

[java] view plaincopy
 
  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。

2)方法区

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

 

[java] view plaincopy
 
  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

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

 

[java] view plaincopy
 
  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如下所示:

 

[java] view plaincopy
 
  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的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:

 

[java] view plaincopy
 
  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栈和本地方法

分享到:
评论

相关推荐

    java内存机制及异常处理

    Java内存机制是Java虚拟机(JVM)的关键组成部分,它管理着程序运行时的数据存储。在Java中,内存主要分为以下几个区域: ...正确理解和运用Java内存机制以及异常处理机制对于开发健壮、高效的Java应用程序至关重要。

    Java 内存模型

    值得注意的是,Java内存模型的讨论和开发过程异常详细和技术化,它涉及了多个学术话题的深入见解和进展。关于这一规范的讨论和开发的档案,可以在Java内存模型的网站上找到,该网站提供了额外的信息,有助于理解该...

    如何解决Java内存泄漏

    ### 如何解决Java内存泄漏 #### 1. 背景 Java凭借其垃圾回收机制大大简化了内存管理,使得开发者无需手动管理内存的释放,从而提升了开发效率。然而,这种自动化管理也可能成为一把双刃剑,特别是当开发人员忽视...

    Java中内存异常StackOverflowError与OutOfMemoryError详解

    Java中内存异常StackOverflowError与OutOfMemoryError详解 Java中内存异常StackOverflowError与OutOfMemoryError是两种常见的错误类型,它们都是 Java 虚拟机(JVM)在运行时可能遇到的问题。本文将详细介绍这两种...

    Java内存机制学习和使用

    ### Java内存机制学习和使用 #### 一、Java内存机制概览 Java内存管理是Java开发人员必须掌握的核心概念之一。良好的内存管理不仅能够提升应用性能,还能避免常见的内存泄漏问题。本文旨在深入探讨Java内存机制,...

    java内存泄漏解决

    ### Java内存泄漏解决方案详解 #### 一、Java内存泄漏概述 在Java开发过程中,经常会遇到内存泄漏的问题,尤其是在长时间运行的应用程序中更为常见。本文将详细介绍如何解决Java内存泄漏问题,帮助开发者更好地...

    JAVA内存溢出问题总结

    JAVA内存溢出问题总结 JAVA 内存溢出问题是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用的内存大于虚拟机能提供的最大内存。内存溢出问题可以从容器和程序类两个方面进行排查,容器问题...

    JAVA内存泄漏分析工具

    Java内存泄漏分析是一个关键的系统优化任务,尤其是在大型企业级应用中,长期运行的系统可能会因为内存泄漏导致性能下降甚至服务中断。"JAVA内存泄漏分析工具"正是一款用于解决此类问题的专业工具,它能帮助开发者...

    深入理解 Java 内存模型

    深入学习 JMM 不仅能帮助开发者理解 Java 并发的基础原理,还能提高程序的并发性能,避免因内存可见性问题导致的程序异常。《深入理解 Java 内存模型》这本书详细探讨了这些主题,是 Java 开发者不可或缺的参考资料...

    java异常 异常的概念 应用

    Java异常处理是编程中至关重要的一个环节,它关乎程序的健壮性和稳定性。在Java中,异常(Exception)被用来表示程序运行时发生的错误或不正常情况。异常并不等同于错误,它是程序设计的一部分,允许我们优雅地处理...

    java异常机制小结

    Error 是 Java 语言中严重错误的 superclass,表示程序中严重的错误,如内存溢出、栈溢出等。Exception 是 Java 语言中非严重错误的 superclass,表示程序中非严重的错误,如除数为零、数组越界等。 三、Java 异常...

    Java内存区域与内存溢出异常.pdf

    Java内存区域与内存溢出异常.pdf

    java内存模型详解

    Java内存模型,简称JMM(Java Memory Model),是Java虚拟机规范中定义的一个抽象概念,它规定了程序中各个线程如何访问共享变量,以及对这些访问进行同步控制的规则。理解Java内存模型对于编写多线程并发程序至关...

    《深入理解JAVA内存模型》PDF

    Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main ...

    Java\课件\JAVA的异常处理机制.ppt

    Java的异常处理机制是Java编程中至关重要的一部分,它主要用于处理程序在运行时可能出现的各种错误和异常情况。这一机制使得开发者能够优雅地处理错误,而不会让整个程序崩溃。以下是关于Java异常处理机制的详细说明...

    基于Java的内存泄露分析及定位

    Java内存管理是一个关键的议题,尤其对于开发大型和长期运行的应用程序来说,内存泄漏可能导致性能下降,甚至引发严重的系统故障。内存泄漏通常发生在程序错误地管理内存,导致某些不再使用的对象无法被垃圾收集器...

    javamemory_JAVA内存监视器_java_

    Java内存监视是优化Java应用程序性能的关键环节,尤其是在处理大规模数据或长时间...通过合理地使用内存监视工具和API,我们可以有效地管理和优化内存使用,避免性能问题和内存异常,从而确保Java应用程序的高效运行。

    Java内存溢出解决办法

    Java内存溢出问题,全称为Java OutOfMemoryError,是Java开发者经常遇到的运行时异常。内存溢出通常发生在程序运行过程中,系统无法为运行的应用程序分配足够的内存资源,导致程序无法正常执行。理解并解决Java内存...

    Java加载dll,导致Java进程内存泄露

    描述中的“NULL”可能是博主在描述问题时的简化表示,通常在编程中“NULL”代表空指针,这可能暗示了在DLL的使用过程中存在空指针异常或者未初始化的指针问题,这也可能是引发内存泄露的原因之一。 标签“源码”和...

    Java 内存溢出解决办法

    Java内存溢出问题通常指的是程序在试图分配内存时,无法找到足够的连续内存空间而抛出的异常。在Java中,内存分为几个区域:堆(Heap)、栈(Stack)、方法区(Method Area,Java 8后被元空间取代)以及程序计数器和...

Global site tag (gtag.js) - Google Analytics