JVM GC的Heap

JVM的一个关键特征是它的GC HeapHeap保存了Java运行期的所有对象,数组。GC可以动态释放Heap中不再使用的空间。在Java程序里,一个对象可以通过关键字new来创建,“创建”对于JVM来说就是在Heap里分配一块空间保存新对象。GC,也就是Garbage collection,既清除Heap里不再使用的对象。为了清除这些对象,GC必须调用这些对象的Finalizer。另为GC还可以合并Heap中的空间碎片。Heap空间碎片是由于不断分配和释放造成的。如果不合并这些碎片,即使有足够的空间,由于没有足够大的连续空间而不得不扩大Heap空间,扩大空间会降低运行性能。

GC算法

目前已经实现了很多GC算法,处理Sun之外,IBMSymantecMicrosoftHP,以及各种开源组织都投入到这项研究。那他们竞争的关键就在于GCHeap。任何一个GC算法都必须做两件事,一,它必须能找到所有的垃圾对象,也就是不再使用的对象,二,它必须可以回收垃圾对象空间。

通常,搜索垃圾的工作,首先建立一组类似于树的结构,树根为root,节点则叫做对象引用。任何一个对象如果在各种结构里能找到它的引用,则成为该对象可使用(reachable)或称对象状态是活动的(live),而任何没有在结构里找到引用的对象则称为垃圾。在JVM里,所有的对象都保存在Heap里,本地变量则保存在Java Stack里,每个线程都有自己的Stack。每个本地变量或是对象引用,或是基本数据类型,例如int, charfloat。因此,线程里保存的只是对象的引用,而对象的实例都保存在Heap中。当一个线程结束,线程里对象引用将被删除,那么这些对象就有可能成为Heap中的垃圾。(“有可能”是因为对象有可能在其他线程中被引用。)

区别可使用对象和垃圾对象有两种方法,他们是引用计数和遍历搜索。引用计数就是在Heap中记录各个对象的引用数。遍历搜索是在树结构里搜索对象引用,并在Heap里标记被引用的对象,遍历后,那些没有标记的对象则是垃圾。

引用计数器

引用计数器保存在对象里,当一个对象被创建时,计数器为1。当其他对象引用这个对象时,该对象的引用计数器加1。当对这个对象的引用结束时,计数器减1。引用计数器为0时,则被看作是垃圾。该算法的缺点是没有遍历功能。该算法已经过时,现在的JVM都采用第二种方法遍历搜索法。

遍历搜索器

        搜索器从树结构的根节点开始遍历,寻找对象引用,并把被引用的对象做标记(Mark)。遍历之后,未作标记的对象被视为垃圾,可被GC回收(Sweep)。

碎片整理

        Heap碎片整理(Compacting collector)有两个步骤,整理和拷贝。这两步用来移动Heap中的对象从而减少碎片。既然好移动对象的位置,当要也要更新对象的引用,但是更新对象引用是会降低VM的性能,因此建立一个对象句柄表,对象引用指向对象句柄,当对象移动时,更新对象的句柄,而不用改变对象引用的值。拷贝步骤就是将Heap的对象移动到新的位置。为了提高拷贝的性能,VM被分为两个区,VM在内只能使用两个中的一个。当使用中的区没有空间后,将所有的对象从该空间拷贝到另一个空间,并继续在另一个空间工作,直到另一个空间满了为止,再把所有对象拷贝回原来的空间。该方法的代价就是需要花费2倍的空间。

 

 

 
发布了96 篇原创文章 · 获赞 8 · 访问量 36万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章