首页 > 系统相关 >JVM运行时的数据区 (内存溢出实例)

JVM运行时的数据区 (内存溢出实例)

时间:2023-05-29 13:01:04浏览次数:614  
标签:常量 区域 int 实例 内存 JVM 方法 public


一、概述

运行时数据区是jvm运行时的内存布局,类装载到内存后存放的位置,为执行引擎提供所需指令和数据。运行时数据区包括:堆、栈、方法区、本地方法栈、pc计数器。

接下来会详细介绍各个部分,并介绍直接内存访问和方法区中的常量池,另外对于每个区域可能发生的内存异常用demo做讲解。

二、详细介绍各部分

1、堆

分配运行时产生的对象分配在堆中,但是并不是一定就分配在堆中,随着运行时编译器优化技术的不断进步,逃逸分析和标量替换技术的不断成熟,对象也可以分配到栈中。由于jvm内存是由虚拟机自己分配和回收,不需要开发人员手工干预,所以jvm一般会提供gc功能,但是jvm spec并没有明确要求必须提供。

整个系统只有一个堆,所有的对象分配都在一个逻辑区域。堆是一个多线程共享的区域,所以对堆中对象的访问就需要考虑并发。(jvm有什么措施)。

在jvm的实现中,一般堆都会划分成不同的区域,比如hotspot vm的堆划分为年轻代Eden、中生代Survivor和年老代Tenured区域,根据对象存活的年龄放到不同的区域,区域的大小可以通过参数设置。这些讲到gc的时候会详细讲解。

如果要存放的对象超过了堆的最大大小,则会抛出OutOfMemoryError,简称OOM异常。

2、栈

栈主要是运行时存放在方法调用信息(编译器已确定占用空间的东西怎么体现)的区域,栈是线程私有的,每个线程都有一个栈,线程生而栈生,线程死而栈灭。

栈中内存不需要额外收集,每次方法调用完成后都会自动回收。hospot vm中可以通过-Xss设置栈大小,默认是2m。

每次方法调用,都会产生一个栈帧,方法调用结束都会弹出栈帧。栈帧主要包括局部变量表、操作数栈、帧数据区。帧数据区又包括运行时解析常量池会用到的常量池指针、方法返回信息、指向异常的信息(还有什么)

所有栈占用的内存大小怎么计算?虚拟机整个的内存-堆内存-方法区内存-pc计数器-本地方法栈?

如果栈可以动态的在堆中分配,则如果分配不了更多的栈内存的时候会抛出OOM异常,否则会抛出StackOverflowError

3、方法区

方法区存class文件加载到内存后的类型信息,如类型描述符、全限定名、接口、字段、方法、属性信息,还有运行时常量池、指向堆中Class实例和ClassLoader实例的信息。另外还存放jit编译产生的本地代码。

方法区在逻辑上是堆的一部分,但是不同的虚拟机有不同的叫法,hotspot叫做non-heap内存,IBM J9和Jrockit则没有这种叫法。hotspot后续版本也会去掉这种叫法,放到native memory的区域

方法区的类型信息也可以卸载,及gc,但是比较严格,像java动态代理生成的代理类经常会被卸载。类型信息要被卸载必须满足这些条件:a、类型所有实例都被回收了 b、Class对象被回收了 c、加载该类的ClassLoader已经被回收 d、还有什么

该区域也会内存溢出,溢出时候抛出OOM异常,如果jar包太多而方法区内存太小或者运行时动态向常量池添加太多东西,就会抛出OOM

4、本地方法栈

执行本地代码的时候用到的栈,hotspot的本地方法栈和栈是同一块区域。

5、pc计数器

指向当前线程将要指向的下一条指令,线程私有的区域,一个线程有一个pc计数器。该区域不会抛出异常。一个字长

6、Direct Memory

java1.4开始提供了NIO,大量读取数据的时候,不用先把数据拷入jvm内存中,直接从os内存读取。所以该区域不占用jvm的堆内存,通过参数-XX:MaxDirectMemorySize设置该区域大小,如果不设置默认跟堆大小一样大。

该区域会抛出OOM异常,何时?

7、常量池

类文件的常量池装载进内存后同样会形成常量池,这是运行时常量池。与类文件常量池不同的是,运行时常量池在使用的时候需要解析,需要把一些entry的符号引用转化成直接引用。

如3提到,此区域在内存不够用时会抛出OOM。

三、例子

1、堆

先创建一个包含大对象的类



1. package
2. public class
3. int[] value;  
4. private static final int M1 = 1024 * 1024;  
5.   
6. public
7. //4 * 1m = 4m
8. this.value = new int[M1];  
9.     }  
10. }


   循环创建类,注释中-Xmx10m是启动时虚拟机参数,最大堆内存是10m




1. package
2.   
3. import
4.   
5. public class
6.   
7. /**
8.      * -Xmx10m
9.      * @param args
10.      */
11. public static void
12. new BigObejct[20];  
13. for(int i = 0;i < 20;i++){  
14. new
15.         }  
16.     }  
17.   
18. }



堆溢出,注意此处OutOfMemoryError: Java heap space表明是堆空间溢出


1. Exception in thread "main"
2. 8)  
3. 15)


  2、栈溢出错误StackOverflowError



1. package
2.   
3. public class
4.   
5. /**
6.      * -Xss500k 如果加上此参数则不会出现StackOverflowError
7.      * @param args
8.      */
9. public static void
10. 5000, 1, 1);  
11.     }  
12. public static void recursiveInvoke(int cnt,int param1,int
13. if(cnt == 0){  
14. return;  
15.         }  
16. int newCnt = cnt - 1;  
17. int
18. int
19.         recursiveInvoke(newCnt, param4, param3);  
20.     }  
21.   
22. }

 不加-Xss参数时候就直接异常了,至少在我的机子上如此;-Xss100k也可以出异常,-Xss500k就正常运行

1. Exception in thread "main"
2. 13)  
3. 19)  
4. ......


 3、方法区

3.1、如果系统非常庞大,比如说一个很大的产品,如ERP系统、CRM系统,里边有非常多的jar包,运行期这些jar都要加载到内存中,而如果方法区设置的过小,就会导致OOM。在客户分阶段上线过程中,第一阶段只上部分模块,比如erp系统只上财务模块,第二期上供应链,第三期上hr、制造,如果前期MaxPermSize设置的过小,就会导致后期部署完相关模块运行过程中出现方法区溢出。此处因为系统代码庞大,代码无法上传。注意此处是PermGen space





1. java.lang.OutOfMemoryError: PermGen space



 3.2、如果动态创建无数的类放到内存中同样会出现这个问题



1. package
2.   
3. import
4.   
5. import
6. import
7. import
8.   
9. public class
10.   
11. /**
12.      * -XX:MaxPermSize=10m
13.      * @param args
14.      * @throws InterruptedException
15.      */
16. public static void main(String[] args) throws
17. for (int i = 0; i < 5000000; i++) {  
18. new
19. class);  
20. false);  
21. new
22. @Override
23. public
24. throws
25. return
26.                 }  
27.             });  
28.             enhancer.create();  
29. 20);  
30.         }  
31.     }  
32. }

 异常:

 



1. Caused by: java.lang.OutOfMemoryError: PermGen space



 4、Direct Memory



1. package
2. import
3.   
4. import
5.   
6. public class
7.   
8. private static final int M1 = 1024 * 1024;  
9.   
10. /**
11.      * @param args
12.      * @throws IllegalAccessException
13.      * @throws IllegalArgumentException
14.      * @throws InterruptedException 
15.      */
16. public static void main(String[] args) throws
17.             IllegalAccessException, InterruptedException {  
18.   
19. class.getDeclaredFields()[0];  
20. true);  
21. null);  
22. for (int i = 0; i < 1000000; i++) {  
23.             unsafe.allocateMemory(M1);  
24. 2);  
25.         }  
26. 100000);  
27.   
28.     }  
29.   
30. }


这部分内存的使用情况,目前visualvm工具中是检测不到的


1. Exception in thread "main"
2.     at sun.misc.Unsafe.allocateMemory(Native Method)  
3. 24)

标签:常量,区域,int,实例,内存,JVM,方法,public
From: https://blog.51cto.com/u_16131764/6370179

相关文章

  • mongodb 实例
    packagecom.jaeson.mongodb;importjava.util.ArrayList;importjava.util.List;importorg.bson.Document;importcom.mongodb.Block;importcom.mongodb.MongoClient;importcom.mongodb.MongoCredential;importcom.mongodb.ServerAddress;//importcom.mongod......
  • Java内存溢出和内存泄露
    一、为什么要了解内存泄露和内存溢出? 1、内存泄露一般是代码设计存在缺陷导致的,通过了解内存泄露的场景,可以避免不必要的内存溢出和提高自己的代码编写水平;2、通过了解内存溢出的几种常见情况,可以在出现内存溢出的时候快速的定位问题的位置,缩短解决故障的时间。 二、基本概念 内......
  • Java 内存模型及GC原理
    一个优秀Java程序员,必须了解Java内存模型、GC工作原理,以及如何优化GC的性能、与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统、实时系统等,只有全面提升内存的管理效率,才能提高整个应用程序的性能。本文将从JVM内存模型、GC工作原理,以及GC的几个关键问题进行探讨,从G......
  • java内存溢出监控
    在程序内增加内存溢出字符串 使用命令启动jar  -XX:+HeapDumpOnOutOfMemoryError这个命令会在报内存溢出的时候生成 .hprof文件(1)java-XX:+HeapDumpOnOutOfMemoryError-jarzxhs.jar(2)java-Xms128m-Xmx256m-XX:+HeapDumpOnOutOfMemoryError-jarzxhs.jar下......
  • 【cplusplus教程翻译】动态内存
    定义变量使用的内存在程序运行前就确定了,有些时候我们希望能在运行期得到内存,可以使用操作符new和deletenew和new[]new操作符可以分配动态内存,new后面需要跟着数据类型,如果需要多个该数据类型的元素,还需加上方括号,这个操作符返回的是新分配内存的头指针,语法是pointer=newtype......
  • Disruptor内存消息队列简单使用
    Disruptor内存消息队列最近在做一个有关使用内存消息队列到功能,比如将日志信息或点击统计信息持久化等操作,开始想着用java到内存队列作为缓冲区,后来在网上搜到Disruptor这个东西,神乎其神到,就简单了解了一下,做了一个demo,感觉还不错,可以用用,有关概念可以自行搜索,下面就简单介绍一下开......
  • 内存管理机制
    Python使用自动内存管理机制,具体来说是使用垃圾回收(GarbageCollection)来管理内存。Python中的垃圾回收器负责跟踪不再使用的对象,并在适当的时候释放它们所占用的内存。Python的内存管理机制主要基于引用计数(ReferenceCounting)和循环垃圾收集(CycleGarbageCollection)。引用......
  • 驱动开发:内核解析内存四级页表
    当今操作系统普遍采用64位架构,CPU最大寻址能力虽然达到了64位,但其实仅仅只是用到了48位进行寻址,其内存管理采用了9-9-9-9-12的分页模式,9-9-9-9-12分页表示物理地址拥有四级页表,微软将这四级依次命名为PXE、PPE、PDE、PTE这四项。关于内存管理和分页模式,不同的操作系统和体系结构......
  • ThreadLocal是否存在内存泄漏问题,如何防止内存泄漏
    ThreadLocal还是不能百分百地让程序员避免内存泄露,如果程序员不谨慎就很可能导致内存泄露?那么今天我们就来聊聊什么样的情况ThreadLocal不会出现内存泄露?什么样的情况会出现内存泄露?我们如何防止内存泄露的情况发生呢?我们这节就会为同学们一一详细解答,那我们先来简单回忆一下Thr......
  • JVM 例子,理解
     一个线程一个栈,栈为线程私有。图中只有一个main线程。某方法返回时,它对应的栈帧也会释放掉。方法区进行类加载,类的字节码中有代码code所有对象都在堆进行分配 main线程的时间片(内核分配的)用完了, 上下文切换,cpu执行t1,要把main线程的栈帧都保存下来......