运行时数据区
第一:PC寄存器
每个运行中的Java程序,每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的地址,在任意时刻,一条Java虚拟机线程只会执行一个方法的代码,这个正在被线程执行的方法称为该线程的当前方法,如果这个方法不是native的,那PC寄存器就保存Java虚拟机正在执行的字节码指令的地址,如果这个方法是native的,那PC寄存器值为undefined,PC寄存器的容量至少能保存一个returnAddress类型的数据或者一个与平台相关的本地指针值。
第二:jvm栈
用于存储栈帧,主要包括一些局部变量与一些过程结果。
*栈帧:用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接,方法返回和异常分派,栈帧随着方法的调用而创建,随着方法的结束而销毁。每个栈帧都有自己的局部变量,操作数栈<看**>和指向当前方法所属类的运行时常量池。
**操作数栈:每一个栈帧内部都有一个称为操作数栈的先进后出栈。栈帧的操作数长度由编译期决定,并且存储在类和接口的二进制表示中。
虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈。每当线程调用一个方法的时候,就对当前状态作为一个帧保存到java stack中(压栈);当一个方法调用返回时,从java stack弹出一个帧(出栈)。Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程。它主要用来存储线程执行过程中的局部变量,方法的返回值,以及方法调用上下文。栈空间随着线程的终止而释放。栈的大小是有一定的限制,这个可能出现StackOverFlow问题。 下面的程序可以说明这个问题。
public class TestStackOverFlow {
public static void main(String[] args) {
test001 t=new test001();
t.check(8450);
// Exception in thread "main" java.lang.StackOverflowError
// no java.lang.StackOverflowError when set 8400
}
}
class test001 {
public int check(int t) {
if (t <= 1) {
return 1;
}else{
check(t - 1);
}
return 0;
}
}
备注:StackOverflowError:在线程执行的过程中,如果栈空间不够用,那么JVM就会抛出此异常,这种情况一般是死递归,或者递归的次数超过栈空间所能承受的最大值。
第三:java堆
在java虚拟机中,堆是可供各条线程共享的运行时内存区域,也是供所有类实例和树组对象分配的内存区域。Heap在Java虚拟机启动的时候就被创建,它存储了被自动内存管理系统(Automatic storage Management System 也就是通常说的垃圾收集器)所管管理的各个对象。一个Java虚拟实例中只存在一个堆空间,因此所有线程都将共享这个堆。每一个java程序独占一个JVM实例,因而每个java程序都有它自己的堆空间,它们不会彼此干扰。但是同一java程序的多个线程都共享着同一个堆空间,就得考虑多线程访问对象(堆数据)的同步问题。 (这里可能出现的异常java.lang.OutOfMemoryError: Java heap space)
第四:方法区(永久存储区) 方法区是可供各条线程共享的运行时数据区,方法区与传统语言中的编译代码存储区或者操作系统的正文段的作用非常的相似,它用于存储每一个类的结构信息,例如:运行时常量池,字段和方法数据,构造函数和普通方法的字节码内容,还包括一些类在类,实例,接口初始化时用到的特殊方法。
在Java虚拟机中,被装载的class的信息存储在Method area的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区。该类型中的类(静态)变量同样也存储在方法区中。与Heap 一样,method area是多线程共享的,因此要考虑多线程访问的同步问题。比如,假设同时两个线程都企图访问一个名为Lava的类,而这个类还没有内装载入虚拟机,那么,这时应该只有一个线程去装载它,而另一个线程则只能等待。Perm代主要保存class,method,filed对象,这部门的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。
(这里可能出现的异常java.lang.OutOfMemoryError: PermGen full)
第五:本地方法栈
Java虚拟机实现可能会使用到传统的栈(通常是”C Stacks”)来支持native方法(指使java以外的其他语言编写的方法),这种栈叫做本地方法栈。对于一个运行中的Java程序而言,它还能会用到一些跟本地方法相关的数据区。当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。本地方法可以通过本地方法接口来访问虚拟机的运行时数据区,不止与此,它还可以做任何它想做的事情。比如,可以调用寄存器,或在操作系统中分配内存等。总之,本地方法具有和JVM相同的能力和权限。 (这里出现JVM无法控制的内存溢出问题native heap OutOfMemory )
Sun JVM
JVM Specification只是抽象的说明了JVM实例按照子系统、内存区、数据类型以及指令这几个术语来描述的, 但是规范并非是要强制规定Java虚拟机实现内部的体系结构,更多的是为了严格地定义这些实现的外部特征。 Sun JVM实现中:Runtime data area(JVM 内存) 五个部分中的Java Stack , Program Counter, Native method stack三部分和规范中的描述基本一致;但对Heap 和 Method Area进行了自己独特的实现。
垃圾分代回收算法(Generational Collecting) 基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。
永久存储区(Permanent Space):永久存储区是JVM的驻留内存,用于存放JDK自身所携带的Class,Interface的元数据,应用服务器允许必须的Class,Interface的元数据和Java程序运行时需要的Class和Interface的元数据。被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM时,释放此区域所控制的内存。
堆空间(The Heap Space):是JAVA对象生死存亡的地区,JAVA对象的出生,成长,死亡都在这个区域完成。堆空间又分别按JAVA对象的创建和年龄特征分为养老区和新生区。
新生区(Young (New) generation space):新生区的作用包括JAVA对象的创建和从JAVA对象中筛选出能进入养老区的JAVA对象。
伊甸园(Eden space):JAVA对空间中的所有对象在此出生,该区的名字因此而得名。也即是说当你的JAVA程序运行时,需要创建新的对象,JVM将在该区为你创建一个指定的对象供程序使用。创建对象的依据即是永久存储区中的元数据。
幸存者0区(Survivor 0 space)和幸存者1区(Survivor1 space):当伊甸园的控件用完时,程序又需要创建对象;此时JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁工作。同时将伊甸园中的还有其他对象引用的对象移动到幸存者0区。幸存者0区就是用于存放伊甸园垃圾回收时所幸存下来的JAVA对象。当将伊甸园中的还有其他对象引用的对象移动到幸存者0区时,如果幸存者0区也没有空间来存放这些对象时,JVM的垃圾回收器将对幸存者0区进行垃圾回收处理,将幸存者0区中不在有其他对象引用的JAVA对象进行销毁,将幸存者0区中还有其他对象引用的对象移动到幸存者1区。幸存者1区的作用就是用于存放幸存者0区垃圾回收处理所幸存下来的JAVA对象。
养老区(Tenure (Old) generation space):用于保存从新生区筛选出来的JAVA对象。
垃圾回收机制
首先当启动J2EE应用服务器时,JVM随之启动,并将JDK的类和接口,应用服务器运行时需要的类和接口以及J2EE应用的类和接口定义文件也及编译后的Class文件或JAR包中的Class文件装载到JVM的永久存储区。在伊甸园中创建JVM,应用服务器运行时必须的JAVA对象,创建J2EE应用启动时必须创建的JAVA对象;J2EE应用启动完毕,可对外提供服务。
JVM在伊甸园区根据用户的每次请求创建相应的JAVA对象,当伊甸园的空间不足以用来创建新JAVA对象的时候,JVM的垃圾回收器执行对伊甸园区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对象所引用的JAVA对象移动到幸存者0区。
如果幸存者0区有足够控件存放则直接放到幸存者0区;如果幸存者0区没有足够空间存放,则JVM的垃圾回收器执行对幸存者0区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对象所引用的JAVA对象移动到幸存者1区。
如果幸存者1区有足够控件存放则直接放到幸存者1区;如果幸存者0区没有足够空间存放,则JVM的垃圾回收器执行对幸存者0区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对象所引用的JAVA对象移动到养老区。
如果养老区有足够控件存放则直接放到养老区;如果养老区没有足够空间存放,则JVM的垃圾回收器执行对养老区区的垃圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并保留那些被其他对象所引用的JAVA对象。如果到最后养老区,幸存者1区,幸存者0区和伊甸园区都没有空间的话,则JVM会报告“JVM堆空间溢出(java.lang.OutOfMemoryError: Java heap space)”,也即是在堆空间没有空间来创建对象。
这就是JVM的内存分区管理,相比不分区来说;一般情况下,垃圾回收的速度要快很多;因为在没有必要的时候不用扫描整片内存而节省了大量时间。
通常大家还会遇到另外一种内存溢出错误“永久存储区溢出(java.lang.OutOfMemoryError: Java Permanent Space)”
- 大小: 20.6 KB
分享到:
相关推荐
JVM规范定义了Java程序如何在特定系统上被加载、解析、执行以及内存管理的一系列规则。 ### JVM架构 JVM主要由以下几个组件构成: 1. **类装载器(ClassLoader)**:负责查找和加载类文件到JVM内存中。 2. **运行...
3. **类加载机制**:JVM遵循"加载(Loading)"、"验证(Verification)"、"准备(Preparation)"、"解析(Resolution)"和"初始化(Initialization)"的五步流程来加载类。双亲委派模型是类加载的一种策略,保证了类...
Java语言规范和JVM规范是理解Java编程基础和高级特性的关键参考资料,它们定义了Java程序的语法、语义以及虚拟机的行为。本压缩包包含了Java6至Java9的版本,涵盖了一系列重要的语言和虚拟机改进,对于Java开发者来...
《JVM8虚拟机规范》深入解析 Java虚拟机(JVM)是Java程序的核心运行环境,它负责解析和执行Java字节码,为开发者提供了跨平台的运行支持。JVM8是Java 8版本的虚拟机规范,包含了对内存布局、数据类型、类文件格式...
总的来说,JVM解析编译过的class文件是一个复杂的过程,涉及众多细节。开发者不仅要理解编译过程,还需要熟悉JVM的内部机制,才能更好地驾驭这个强大的平台。通过阅读相关博文,如给定的链接,可以进一步深入了解...
并且必须在finally从句<br>中释放,如果没有答出在finally中释放不得分.就如Connection没有在finally中关闭一<br>样.连最基本的资源释放都做不好,还谈什么多线程编程.<br>6.EJB规范规定EJB中禁止的操作有哪些?(15分)...
Java语言规范和JVM虚拟机规范是理解Java编程基础及其执行机制的核心文档,它们由Oracle官方发布,确保了Java开发的准确性和一致性。本压缩包包含的文件详细阐述了Java编程语言的各个方面以及Java虚拟机(JVM)的工作...
《JVM规范与深入理解》这个主题涵盖了Java虚拟机(Java Virtual Machine)的全面解析,旨在帮助开发者深入了解JVM的工作原理及其对程序性能的影响。在这个主题中,我们主要关注两个核心资源:周志明的《深入理解Java...
虚拟机会保证子<client>方法执行之前,父类的<client>方法已经执行完毕,如果一个类中没有对静态变量赋值也没有静态语句块,那么编译器可以不为这个类生成<client>()方法。 类加载器 虚拟机设计团队把加载动作放到...
<groupId>de.odysseus.juel</groupId> <artifactId>juel-api</artifactId> <version>2.2.7</version> </dependency> <dependency> <groupId>de.odysseus.juel</groupId> <artifactId>juel-impl</artifactId> ...
方法区是JVM规范中的一部分,不同虚拟机实现时方法区的具体内容和管理方式可能会有所不同。 #### 运行时常量池 运行时常量池是方法区的一部分,它存放编译期生成的各种字面量和符号引用,并在类加载后被存放至方法...
详细介绍了jvm虚拟机规范,很好 第一章引言 第二章 java概念 第三章 java虚拟机结构 第四章 class文件格式 第五章 常熟池解析 第六章 java虚拟机指令集 第七章 为java虚拟机编译 第八章 线程和锁 第九章 优化 第十章...
5. **初始化**:最后,JVM执行类的初始化方法(<clinit>),这包括静态变量的初始化和静态代码块的执行。当且仅当类被首次主动使用时,才会进行初始化。 6. **执行**:一旦主类完成初始化,JVM的执行引擎开始运行...
- JVM规范定义了不同的内存区域,包括程序计数器、Java虚拟机栈、本地方法栈、堆和方法区(在Java 8之后变为元空间)。 - Java虚拟机栈:每个线程都有一个独立的栈,用于存储方法调用的状态,包括局部变量、操作数...
- **类文件解析**:JVM将类文件中的字节码转换成计算机能够理解的指令执行。 #### 10. 常用工具 - **VisualVM**:是一个可以监控运行时的Java应用程序和环境的工具。 - **Memory Analyzer**:用于分析Java堆转储的...
4. 解析:JVM解析类中的符号引用,将其转换为直接引用。这涉及类、接口、字段和方法的引用。 5. 初始化:最后,JVM执行类的初始化方法(<clinit>),对静态变量进行显式初始化。 用Java解析class文件,意味着我们...
### 深入解析JVM:Java虚拟机的精髓与挑战 #### JVM概览与重要性 JVM,即Java Virtual Machine(Java虚拟机),是Java程序员必须掌握的核心技术之一。初学者通常从简单的“HelloWorld”程序开始,逐渐接触更复杂的...
Java程序中的类在运行时动态加载,这一过程包括加载、验证、准备、解析和初始化五个阶段。加载阶段找到类的二进制数据;验证确保数据符合Java规范;准备阶段为静态变量分配内存并初始化为默认值;解析将符号引用转换...
4. **运行时数据区**:JVM规范定义了程序计数器、虚拟机栈、本地方法栈、堆和方法区这五个主要的运行时数据区。每个线程都有自己的程序计数器、虚拟机栈和本地方法栈,而堆和方法区则是所有线程共享的。 5. **字节...