首页 > 代码库 > JVM

JVM

详细:

JVM的垃圾回收是多种机制的混合。JVM会根据程序运行状况,自行决定采用哪种垃圾回收。

  • "mark and sweep"。这种机制下,每个对象将有标记信息,用于表示该对象是否可到达。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到所有的可到达对象,并标记(mark)。随后,JVM需要扫描整个堆,找到剩余的对象,并清空这些对象所占据的内存。

  • 另一种是"copy and sweep"。这种机制下,堆被分为两个区域。对象总存活于两个区域中的一个。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到可到达对象,将可到达对象复制到空白区域中并紧密排列,修改由于对象移动所造成的引用地址的变化。最后,直接清空对象原先存活的整个区域,使其成为新的空白区域。

可以看到,"copy and sweep"需要更加复杂的操作,但也让对象可以紧密排列,避免"mark and sweep"中可能出现的空隙。在新建对象时,"copy and sweep"可以提供大块的连续空间。因此,如果对象都比较"长寿",那么适用于"mark and sweep"。如果对象的"新陈代谢"比较活跃,那么适用于"copy and sweep"。

上面两种机制是通过分代回收(generational collection)混合在一起的。每个对象记录有它的世代(generation)信息。所谓的世代,是指该对象所经历的垃圾回收的次数。世代越久远的对象,在内存中存活的时间越久。

根据对Java程序的统计观察,世代越久的对象,越不可能被垃圾回收(富人越富,穷人越穷)。因此,当我们在垃圾回收时,要更多关注那些年轻的对象。

堆分为三代。

  • 其中的永久世代(permanent generation)中存活的是Class对象。这些对象不会被垃圾回收。我们在RTTI中已经了解到,每个Class对象代表一个类,包含有类相关的数据与方法,并提供类定义的代码。每个对象在创建时,都要参照相应的Class对象。每个对象都包含有指向其对应Class对象的引用。

  • 年轻世代(young generation)和成熟世代(tenured generation)需要进行垃圾回收。年轻世代中的对象世代较近,而成熟世代中的对象世代较久。

年轻世代进一步分为三个区域

  • eden(伊甸): 新生对象存活于该区域。新生对象指从上次GC后新建的对象。

  • from, to: 这两个区域大小相等,相当于copy and sweep中的两个区域。

当新建对象无法放入eden区时,将出发minor collection。JVM采用copy and sweep的策略,将eden区与from区的可到达对象复制到to区。经过一次垃圾回收,eden区和from区清空,to区中则紧密的存放着存活对象。随后,from区成为新的to区, to区成为新的from区。

如果进行minor collection的时候,发现to区放不下,则将部分对象放入成熟世代。另一方面,即使to区没有满,JVM依然会移动世代足够久远的对象到成熟世代。

如果成熟世代放满对象,无法移入新的对象,那么将触发major collection。JVM采用mark and sweep的策略,对成熟世代进行垃圾回收。

young代采用复制算法,从eden复制到survival或者 从eden和一个survival 复制到另外一个survival。
old代采用标记压缩。

采用不同的策略的原因在于两者之间的回收执行频率不一致。而且old代中的对象很少被回收,采用标记压缩减轻了复制压力。



JVM 

_ Class Loader 类加载器

类加载器的作用是加载类文件到内存,比如编写一个HelloWord.java 程序,然后通过javac

编译成class 文件,那怎么才能加载到内存中被执行呢?Class Loader 承担的就是这个责任,那

不可能随便建立一个.class 文件就能被加载的,Class Loader 加载的class 文件是有格式要求,

友情提示:Class Loader 只管加载,只要符合文件结构就加载,至于说能不能运行,则不是

它负责的,那是由Execution Engine 负责的。

_ Execution Engine 执行引擎

执行引擎也叫做解释器(Interpreter),负责解释命令,提交操作系统执行。

_ Runtime data area 运行数据区

运行数据区是整个JVM 的重点。我们所有写的程序都被加载到这里,之后才开始运。


整个JVM 框架由加载器加载文件,然后执行器在内存中处理数据,需要与异构系统交互是可以

通过本地接口进行,瞧,一个完整的系统诞生了!

2 JVM 的内存管理

所有的数据和程序都是在运行数据区存放,它包括以下几部分:

_ Stack 栈

栈也叫栈内存,是Java 程序的运行区,是在线程创建时创建,它的生命期是跟随线程的生命

期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束,该栈就Over。

问题出来了:栈中存的是那些数据呢?又什么是格式呢?

栈中的数据都是以栈帧(Stack Frame)的格式存在

,栈帧是一个内存区块,是一个数据集,是

一个有关方法(Method)和运行期数据的数据集

Heap 堆内存

一个JVM 实例只存在一个堆类存,堆内存的大小是可以调节的。类加载器读取了类文件后,需

要把类、方法、常变量放到堆内存中,以方便执行器执行,堆内存分为三部分:

  1. Step 1: Marking

    The first step in the process is called marking. This is where the garbage collector identifies which pieces of memory are in use and which are not.

  1. Step 2: Normal Deletion

    Normal deletion removes unreferenced objects leaving referenced objects and pointers to free space.

  1. Step 2a: Deletion with Compacting

    To further improve performance, in addition to deleting unreferenced objects, you can also compact the remaining referenced objects. By moving referenced object together, this makes new memory allocation much easier and faster.


JVM