JVM 规范与 Sun JVM 实现、运行时数据区域、垃圾分代回收算法

目录

JVM 规范(Specification)

Runtime data area 运行时数据区域

Sun JVM 规范实现

垃圾分代回收算法(Generational Collecting) 


JVM 规范(Specification)

1、JVM Specification(规范)中的 JVM 整体架构如下图:

运行时数据区域中的方法区、heap:所有线程共享使用
其余3个白色的则各个线程独有,互补干扰​​​​​​

1、主要包括两个子系统和两个组件:Class Loader(类加载器)子系统,Execution Engine(执行引擎)子系统;Runtime data area(运行时数据区域)组件,Native interface(本地接口)组件。

2、Class loader 子系统:根据给定的全限定类名(如 java.lang.Object)来装载 class 文件的内容到 Runtime data area 中的方法区。Java 程序员可以 extends java.lang.ClassLoader 类来自定义 Class loader。

3、Execution engine 子系统:执行 classes 中的指令。任何 JVM 规范的实现(JDK),其核心就是 Execution engine。目前 JVM 规范的实现主要有 sun 公司的 JDK、JRE(现在是Oracle的了),以及 IBM 的 JDK、JRE,因为都遵循 JVM 规范,所以功能上基本无异,好坏程度主要取决于它们各自实现的 Execution engine。每个运行中的线程都有一个 Executon engine 的实例。

4、Native interface 组件:与 Native libraries 交互,是与其它编程语言交互的接口。

5、Runtime data area 组件:这个组件是 JVM 中的内存,也是核心部分,下面将对它进行详细介绍。

Runtime data area 运行时数据区域

1、Runtime data area 组件是 JVM 中的内存,整体架构图如下:

2、Runtime data area 主要包括五个部分:Heap (堆)、Method Area(方法区域)、Java Stack(java的栈)、Program Counter(程序计数器)、Native method stack(本地方法栈)。

3、Heap 和 Method Area 是被所有线程的共享使用的;而 Java stack, Program counter 和Native method stack 是以线程为粒度的,每个线程独自拥有。

Heap(堆)
1、Java 程序在运行时创建的所有类实例或数组都放在同一个堆中。

2、一个 Java 程序独占一个 JVM 实例,互补干扰,一个 JVM 实例只存在一个堆空间,同一 Java 程序中的所有线程都共享这个堆,所以得考虑多线程访问对象(堆数据)的同步问题。

3、可能出现的异常为:java.lang.OutOfMemoryError:Java heap space

Method area(方法区)
1、Java 虚拟机中,被装载的 class 的信息存储在 Method area 的内存中。

2、当虚拟机装载某个类型时,它使用类装载器定位相应的 class 文件,然后读入这个 class 文件的内容,并把它传输到虚拟机中。然后虚拟机提取其中的类型信息,同时将它存储到方法区。该类型中的类(静态)变量同样也存储在方法区中

3、与 heap 一样,method area 也是多线程共享的,需要考虑多线程访问的同步问题。比如:两个线程都企图访问一个名为 HelloWorld 的类,而这个类还没有装载入虚拟机,那么这时应该只有一个线程去装载它,另一个线程只能等待。

4、可能出现的异常:java.lang.OutOfMemoryError:PermGen full(permanent generation full)

Java Stack(虚拟机栈)
1、Java stack 以帧为单位保存线程的运行状态

2、虚拟机只会直接对 Java stack 执行两种操作;以帧为单位的压栈或出栈。每当线程调用一个方法时,就对当前状态作为一个帧保存到 Java stack 中(压栈);当一个方法返回时,从 Java stack 弹出一个帧(出栈)。

3、栈的大小是有一定的限制的,可能出现的问题为:StackOverFlow

Program counter(程序计数器)
1、每个运行中的 Java 程序,每一个线程都有它自己的 PC寄存器,在线程启动时创建的。(延伸:寄存器是 CPU 的组成部分,是一个容量有限的高速存储部件,它们可用来暂存指令、数据和地址)

2、PC寄存器的内容总是指向下一条将被执行指令的"地址",这里的"地址"可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。

Native method stack(本地方法栈)
1、对于一个运行中的 Java 程序而言,它可能会用到一些跟本地方法相关的数据区。当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。

2、本地方法可以通过本地方法接口来访问虚拟机的运行时数据区,不止与此,它还可以做任何它想做的事情。比如,可以调用寄存器,或在操作系统中分配内存等。

3、总之,本地方法具有和 JVM 相同的能力和权限。 (这里可能出现 JVM 无法控制的内存溢出问题native heap OutOfMemory )

Sun JVM 规范实现

1、本节主要介绍 Sun JVM 中对 JVM Specification 的实现(内存部分)。

2、已经说过 JVM Specification(规范)只是抽象的说明了 JVM 实例按照子系统、内存区、数据类型以及指令这几个术语来描述,规范并非是要强制规定 Java 虚拟机实现内部的体系结构,更多的是为了严格地定义这些实现的外部特征。所以如 Sun JVM 实现与 IMB JVM 实现细节上略有不同。

3、Sun JVM 实现中:Runtime data area(JVM 内存) 五个部分中的 Java Stack , Program Counter, Native method stack 三部分和规范中的描述基本一致;但对 Heap 和 Method Area 进行了自己独特的实现。这个实现和 Sun JVM 的 Garbage collector(垃圾回收)机制有关。下面的"垃圾分代回收算法"会进行详细描述。

垃圾分代回收算法(Generational Collecting) 

1、分代回收算法是基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述3代中的一个)进行回收。

2、现在 sum jvm 的垃圾回收器(从J2SE1.2开始)都是使用此算法。

Young(年轻代)

1)Young(年轻代)是 JVM specification 中 Heap的一部份。
2)年轻代分三个区。一个 Eden(伊甸园)区,两个 Survivor(幸存者)区。
3)大部分对象在 Eden 区中生成,当 Eden 区已满时,还存活的对象将被复制到 Survivor区(两个中的一个),当这个 Survivor 区已满时,此区的存活对象将被复制到另外一个Survivor 区,当这个 Survivor 区也满了的时候,从第一个 Survivor 区复制过来的并且此时还存活的对象,将被复制 "年老区"。
4)需要注意 Survivor 的两个区是对称平等的,没先后关系,任何时候 Survivor 区总有一个是空的。

Tenured(年老代)

1)Tenured(年老代)是 JVM specification 中 Heap 的一部份 
2)年老代存放从年轻代存活的对象,一般来说年老代存放的都是生命期较长的对象

Perm(持久代) 

1)Perm(Permanent 持久代) 是 JVM specification 中的 Method area 用于存放静态文件,如今静态 Java 类、静态方法、静态成员变量等。
2)持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class,例如 Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。
3)持久代大小通过 -XX:MaxPermSize= 进行设置。

可以结合JVM 垃圾回收工作运作流程一起理解。

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/88925921