`

Java_JVM的内存溢出异常

    博客分类:
  • Java
 
阅读更多

via: http://codelog.lofter.com/post/bfe88_18216e

 

JVM的内存溢出异常

在Java虚拟机规范的描述中,除了PC(程序计数器)寄存器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能。当发生OutOfMemoryError异常时,无法用try...catch捕捉。

 

在开始讲解之前,在这里先简单介绍下虚拟机启动相关的一些内存设置参数。因为OutOfMemoryError异常发生,与这些参数的设置密切相关。

 

举例说明含义:

-Xss128k 每个线程的java栈大小,一个线程java栈所有栈帧大小总和最大允许的尺寸128k。

-Xms128m 表示JVM Heap(堆内存)最小尺寸128MB,初始分配

-Xmx512m 表示JVM Heap(堆内存)最大允许的尺寸256MB,按需分配。

-XX:PermSize=20M 设置方法区的初始大小

-XX:MaxPermSize=30M 设置方法区的最大值

 

Java栈溢出

在Java虚拟机规范中,对这个区域规定了两种异常状况:StackOverflowError和OutOfMemoryError异常。

 

1.StackOverflowError异常

每当java程序代码启动一个新线程时,Java虚拟机都会为它分配一个Java栈。Java栈以帧为单位保存线程的运行状态。当线程调用java方法时,虚拟机压入一个新的栈帧到该线程的java栈中。只要这个方法还没有返回,它就一直存在。如果线程的方法嵌套调用层次太多(如递归调用),随着java栈中帧的逐渐增多,最终会由于该线程java栈中所有栈帧大小总和大于-Xss设置的值,而产生StackOverflowError内存溢出异常。例子如下:

 

/**  

  * VM Args: -Xss128k  

  */ 

 public class Test {  

     private int count = 0;  

     public static void main(String[] args) {  

         new Test().method();  

     }  

     public void method() {  

         System.out.println(++count);  

         method();  

     }  

 } 

-Xss为128k。其中的一次测试结果为,当count的值累加到2312时,发生如下异常:

Exception in thread "main" java.lang.StackOverflowError  

    at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:58)  

    at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:392)  

    at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:447)  

    at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)  

    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:252)  

    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)  

    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)  

    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)  

    at java.io.PrintStream.write(PrintStream.java:476)  

    at java.io.PrintStream.print(PrintStream.java:547)  

    at java.io.PrintStream.println(PrintStream.java:686)  

    at jvm.Test.method(Test.java:17) 

修改-Xss为1280k。其中的一次测试结果为,当count的值累加到26888时,发生StackOverflowError异常。随着-Xss参数值的增大,可以嵌套的方法调用层次也相应增加。

综上所述,StackOverflowError异常是由于方法调用的层次太深,最终导致为某个线程分配的所有栈帧大小总和大于-Xss设置的值,从而发生StackOverflowError异常。

 

2.OutOfMemoryError异常

java程序代码启动一个新线程时,没有足够的内存空间为该线程分配java栈(一个线程java栈的大小由-Xss参数确定),jvm则抛出OutOfMemoryError异常。例子如下:

/**  

  * VM Args: -Xss128k  

  */ 

 public class Test {  

     public static void main(String[] args) {  

         int count = 0;  

         while (true) {  

             Thread thread = new Thread(new Runnable() {  

                 public void run() {  

                     while (true) {  

                         try {  

                             Thread.sleep(5000);  

                         } catch (Exception e) {}  

                     }  

                 }  

             });    

             thread.start();  

             System.out.println(++count);  

         }  

     }  

   

 } 

-Xss为128k。其中的一次测试结果为,当count的值累加到11887时,发生如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread  

    at java.lang.Thread.start0(Native Method)  

    at java.lang.Thread.start(Thread.java:640)  

    at jvm.Test.main(Test.java:20) 

修改-Xss为1280k。其中的一次测试结果为,当count的值累加到1270时,发生OutOfMemoryError异常。随着-Xss参数值的增大,java程序可以创建的总线程数越少。

 

Java堆溢出

 

Java堆用于储存对象实例。当需要为对象实例分配内存,而堆的内存占用又已经达到-Xmx设置的最大值。将会抛出OutOfMemoryError异常。例子如下:

/**  

  * VM Args: -Xmx5m  

  */ 

 public class Test {  

     public static void main(String[] args) {  

         int count = 0;  

         List<Object> list = new ArrayList<Object>();  

         while (true) {  

             list.add(new Object());  

             System.out.println(++count);  

         }  

     }  

   

 } 

-Xmx为5m。其中的一次测试结果为,当count的值累加到297868时,发生如下异常:

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

    at java.util.Arrays.copyOf(Arrays.java:2760)  

    at java.util.Arrays.copyOf(Arrays.java:2734)  

    at java.util.ArrayList.ensureCapacity(ArrayList.java:167)  

    at java.util.ArrayList.add(ArrayList.java:351)  

    at jvm.Test.main(Test.java:15) 

修改-Xmx为10m。其中的一次测试结果为,当count的值累加到670205时,发生OutOfMemoryError异常。随着-Xmx参数值的增大,java堆中可以存储的对象也越多。

 

方法区溢出

方法区用于存放java类型的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。在类装载器加载class文件到内存的过程中,虚拟机会提取其中的类型信息,并将这些信息存储到方法区。当需要存储类信息而方法区的内存占用又已经达到-XX:MaxPermSize设置的最大值。将会抛出OutOfMemoryError异常。对于这种情况的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出。这里需要借助CGLib直接操作字节码运行时,生成了大量的动态类。例子如下:

/**  

   * VM Args: -XX:MaxPermSize=50M  

   */ 

  public class Test {  

      public static void main(String[] args) {  

          int count = 0;  

          while (true) {  

               Enhancer enhancer = new Enhancer();  

               enhancer.setSuperclass(Test.class);  

               enhancer.setUseCache(false);  

               enhancer.setCallback(new MethodInterceptor() {  

                  public Object intercept(Object obj, Method method, Object[] args,   

                    MethodProxy proxy) throws Throwable {  

                      return proxy.invoke(obj, args);  

                  }  

               });  

               enhancer.create();  

               System.out.println(++count);  

          }  

      }  

    

  } 

-XX:MaxPermSize为50m。其中的一次测试结果为,当count的值累加到3953时,发生如下异常:

Caused by: java.lang.OutOfMemoryError: PermGen space  

    at java.lang.ClassLoader.defineClass1(Native Method)  

    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)  

    at java.lang.ClassLoader.defineClass(ClassLoader.java:615)  

    ... 8 more 

修改-XX:MaxPermSize为100m。其中的一次测试结果为,当count的值累加到8022时,发生OutOfMemoryError异常。随着-XX:MaxPermSize参数值的增大,java方法区中可以存储的类型数据也越多。

 

相关的参考资料:

1.深入Java虚拟机(原书第2版)

2.深入理解Java虚拟机:JVM高级特性与最佳实践

分享到:
评论

相关推荐

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    第2章 Java内存区域与内存溢出异常 / 24 2.1 概述 / 24 2.2 运行时数据区域 / 25 2.2.1 程序计数器 / 25 2.2.2 Java虚拟机栈 / 26 2.2.3 本地方法栈 / 27 2.2.4 Java堆 / 27 2.2.5 方法区 / 28 2.2.6 运行...

    深入理解Java虚拟机——Java内存区域与内存溢出异常.xmind

    这是自己读《深入理解Java虚拟机》时候用XMind建立的思维导图,目的是为了能够帮助自己整理、梳理相关的知识以及方便自己日后的回顾,帮助自己建立起关于JVM的知识体系,里边也有一些对相关内容的补充,通过备注的...

    jvm内存分析工具mat安装包

    JVM内存dump分析工具MAT独立安装包,分析内存溢出利器,可以准确定位内存异常原因,解决问题,MemoryAnalyzer-1.10.0.20200225.zip

    Java进阶教程解密JVM视频教程

    * 在内存结构章节,能够学习掌握 JVM内存溢出现象,堆栈内存结构,利用内存诊断工具排查问题。彻底分析 StringTable的相关知识与性能优化,掌握直接内存分配原理和释放手段。 * 在垃圾回收章节,不仅会介绍垃圾回收...

    Tomcat内存溢出的三种情况及解决办法分析

    可能是由于这些框架会动态class,而且jvm的gc是不会清理PemGen space的,导致内存溢出。 这一个一般是加大-XX:PermSize -XX:MaxPermSize 来解决问题。 -XX:PermSize 永久保存区域初始大小 -XX:PermSize 永久...

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...

    学习JVM之java内存区域与异常

    关于JVM内存区域的知识对于初学者来说其实是很重要的,了解Java内存分配的原理,这对于以后JAVA的学习会有更深刻的理解。下面来看看详细介绍。

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第4节jvm初体验-内存溢出问题的分析与解决 [免费观看] 00:17:59分钟 | 第5节jvm再体验-jvm可视化监控工具 [免费观看] 00:21:17分钟 | 第6节杂谈 [免费观看] 00:12:37分钟 | 第7节Java的发展历史00:27:24分钟 | ...

    Java提高篇——Java异常处理

    本文来自于cnblogs,文章主要从基础概念说起,又讲解了体系结构,Java的异常处理机制,异常链等相关,详细内容请看下文。异常是程序中的一些错误,...网络通信时连接中断,或者JVM内存溢出。这些异常有的是因为用户错误

    java8源码-jvm-study:jvm-study

    堆内存溢出 (-Xms30m -Xmx30m -XX:+PrintGCDetails) GC overhead limit exceeded: gc占用98%的资源回收效率不足2%的(-Xms30m -Xmx30m) Metaspace:方法区异常----(XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=...

    Java入门两周旅 (Day12) Java 异常处理

    Java 异常处理 没有程序能够始终正常运行,Java 语言的设计者...例如,JVM 内存溢出。一般地,程序不会从错误中恢复。 Exception : 程序本身可以处理的异常 IOException RuntimeException 异常分层结构 Java 语言包含一

    java8rt.jar源码-JVM:学习JVM

    第2章:java内存模型和内存溢出异常 1.运行时数据区域 1.程序计数器:线程私有 2.java虚拟机栈:线程私有,虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧,存储局部变量表、操作数...

    Java虚拟机

    第2章 Java内存区域与内存溢出异常 2.1 概述 2.2 运行时数据区域 2.2.1 程序计数器 2.2.2 Java虚拟机栈 2.2.3 本地方法栈 2.2.4 Java堆 2.2.5 方法区 2.2.6 运行时常量池 2.2.7 直接内存 2.3 HotSpot...

    Java常见面试问题整理.docx

    线程共享:异常:OOM 内存溢出 1.Java堆:对于大多数应用来说,Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,...

    Java 异常处理

    Java 异常处理 异常是程序中的一些错误,但并不是所有的错误...网络通信时连接中断,或者JVM内存溢出。 这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。- 要理解Java异常处

    UnderstandingTheJVM:《深入理解Java虚拟机 - Jvm高级特性与最佳实践(第三版)》阅读笔记

    本repository为《深入理解Java虚拟机 - Jvm高级特性与最佳实践(第三版)》阅读笔记,因为第一章主要讲的是Java的发展历史,这里就不做笔记,直接从第2章的"Java内存区域与内存溢出异常"讲起。 第二部分 自动内存...

    涵盖了90%以上的面试题

    JVM内存模型1.7和1.8的区别 如何判断一个对象是否是垃圾对象 垃圾回收算法 Minor GC和Full GC 垃圾收集器 集合的继承体系 Collection 和 Collections的区别。 如何通过jdbc访问数据库 JDBC处理事务采用什么方法 ...

    JAVA面试题最全集

    50.JAVA语言如何进行异常处理,关键字:thorws,throw,try,catch,finally 51.Object类(或者其子类)的finalize()方法在什么情况下被调用? 52.一个“.java”原文件中是否可以包括多个类(不是内部类)? 53.掌握...

    java 面试题 总结

    比如说内存溢出。不可能指望程序能处理这样的情况。 exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。 16、同步和异步有何异同,在什么情况下分别使用他们?举例说明。 ...

Global site tag (gtag.js) - Google Analytics