Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 411|回复: 0

jvm的内存溢出异常

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-7 15:17:50 | 显示全部楼层 |阅读模式

          1.jvm的内部体系结构浅析

          2.jvm的几个运行时数据区域

          3.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内存溢出异常。例子如下:

     1 /**
     2  * VM Args: -Xss128k
     3  */
     4 public class Test {
     5     
     6     private int count = 0;
     7 
     8     public static void main(String[] args) {
     9         new Test().method();
    10     }
    11     
    12     public void method() {
    13         System.out.println(++count);
    14         method();
    15     }
    16 
    17 }

     -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异常。例子如下:

     1 /**
     2  * VM Args: -Xss128k
     3  */
     4 public class Test {
     5     
     6     public static void main(String[] args) {
     7         int count = 0;
     8         while (true) {
     9             Thread thread = new Thread(new Runnable() {
    10                 public void run() {
    11                     while (true) {
    12                         try {
    13                             Thread.sleep(5000);
    14                         } catch (Exception e) {}
    15                     }
    16                 }
    17             });  
    18             thread.start();
    19             System.out.println(++count);
    20         }
    21     }
    22 
    23 }

     -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异常。例子如下:

     1 /**
     2  * VM Args: -Xmx5m
     3  */
     4 public class Test {
     5     
     6     public static void main(String[] args) {
     7         int count = 0;
     8         List<Object> list = new ArrayList<Object>();
     9         while (true) {
    10             list.add(new Object());
    11             System.out.println(++count);
    12         }
    13     }
    14 
    15 }

     -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直接操作字节码运行时,生成了大量的动态类。例子如下:

     1 /**
     2   * VM Args: -XX:MaxPermSize=50M
     3   */
     4  public class Test {
     5      
     6      public static void main(String[] args) {
     7          int count = 0;
     8          while (true) {
     9               Enhancer enhancer = new Enhancer();
    10               enhancer.setSuperclass(Test.class);
    11               enhancer.setUseCache(false);
    12               enhancer.setCallback(new MethodInterceptor() {
    13                  public Object intercept(Object obj, Method method, Object[] args, 
    14                    MethodProxy proxy) throws Throwable {
    15                      return proxy.invoke(obj, args);
    16                  }
    17               });
    18               enhancer.create();
    19               System.out.println(++count);
    20          }
    21      }
    22  
    23  }

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

    3.互联网相关的文章

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-3 22:10 , Processed in 0.055461 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表