首页 > 系统相关 >Java_JVM的内存溢出异常

Java_JVM的内存溢出异常

时间:2023-04-14 11:39:06浏览次数:40  
标签:count java Test 线程 内存 JVM OutOfMemoryError Java



 

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高级特性与最佳实践

标签:count,java,Test,线程,内存,JVM,OutOfMemoryError,Java
From: https://blog.51cto.com/u_16070335/6189747

相关文章

  • Java_Double&BigDecimal
    importjava.math.BigDecimal;importjava.math.MathContext;publicclassBigDecimalTest{/***@paramargs*@referencearchie2010*@function实现将double类型的值转换为BigDecimal类型的值的不同途径以及各途径间的区别*......
  • Java_获取变量的类型
    如果是对象,那么可以使用getClass().getName()方法获得该对象的类名,然,还有就是利用反射机制获取原数据类型的,这个时候如果需要确定类型, 同样的,反射机制返回值是对象,比如对于类属性的返回,是Field对象,可以 通过里面的getType().getName()获得该属性的类型名称,下面一个例子:Type ......
  • Java_procedure with return value(oracle)
    Java调用Oracle中有返回值的存储过程1) 在编写存储过程时,输入参数用in(如果不写默认为in),输出参数用out --编写过程,要求输入雇员编号,返回雇员姓名。 createorreplaceproceduregetNameByNo(noinnumber,nameoutvarchar2)is begin  selectenameintonamefrom......
  • Java使用TensorFlow
    Java可以使用TensorFlow,TensorFlow为Java提供了一个API,它可以让Java开发者使用TensorFlow构建和训练深度学习模型。以下是如何在Java中使用TensorFlow的基本步骤:首先,需要安装TensorFlow的JavaAPI,可以从TensorFlow官网下载安装包,或者通过Maven或Gradle添加依赖。然后,在Java......
  • MariaDB_About the MariaDB Java Client
    via: https://mariadb.com/kb/en/about-the-mariadb-java-client/ IntroductionTheMariaDBClientLibraryforJavaApplicationsisaType4JDBCdriver.ItwasdevelopedspecificallyasalightweightJDBCconnectorforusewithMySQLandMariaDBdatabaseser......
  • Java中File类中常用的一些方法
    File.delete()删除文件或文件夹目录。File.createNewFile()创建一个新的空文件。File.mkdir()创建一个新的空文件夹。File.list()获取指定目录下的文件和文件夹名称。File.listFiles()获取指定目录下的文件和文件夹对象。File.exists......
  • 半小时实现Java网络爬虫框架
    最近在做一个搜索相关的项目,需要爬取网络上的一些链接存储到索引库中,虽然有很多开源的强大的爬虫框架,但本着学习的态度,自己写了一个简单的网络爬虫,以便了解其中的原理。今天,就为小伙伴们分享下这个简单的爬虫程序!!首先介绍每个类的功能:DownloadPage.java的功能是下载此超链接的页......
  • Java_判断操作系统类型
    Java判断操作系统类型(适用于各种操作系统)/***平台*@authorisea533*/publicenumEPlatform{Any("any"),Linux("Linux"),Mac_OS("MacOS"),Mac_OS_X("MacOSX"),Windows("Windows"),OS2("OS......
  • Java基础---数据类型
    数据类型Java的两大数据类型:内置数据类型、引用数据类型内置数据类型Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。byte、short、int、long、float、double、char、boolean基本类型范围byte:(8位)-128~127short:(26......
  • jvm 类加载
    将字节码文件加载到jvm,并创建对应的字节码对象,然后对其进行验证、初始化等操作共5个阶段:加载、验证、准备、解析、初始化,这里只记录【加载】里的类加载器和双亲委派加载的是字节码文件通过类加载器ClassLoader把字节码文件在堆中生成代表这个class文件的java.lang.Clas......