[置顶] 垃圾回收算法之路

垃圾收集算法

  在上一节我说了我们应该回收哪些内存,什么时候回收,接下来我会谈怎样回收?

  对于这样回收在think in java中也有相同的介绍,但是非常的少,译者也翻译得不太详细,之前读了think in java再看一遍 深入理解java虚拟机,加深了很多理解。

标记清除算法

  标记-清除算法是最基础的算法,和他名字一样分为两个部分,“标记”和“清除”:首先标记所有需要回收的对象,在标记完成后统一回收被标记的对象。这个算法有两个问题:第一个是效率:标记和清除效率不高;第二个是空间问题:会产生大量不连续的碎片,无法找到足够的连续内存而会触发另外一次GC。

复制算法

  复制算法用于解决效率,在新生代(在另篇帖子有介绍)里面常用的算法,具体思想是:可用内存按容量分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活着的对象复制到另外一块上面去,然后把使用过的内存空间清理掉。这样很好的解决了效率和空间碎片的问题,但是会存在一个把内存缩小的问题。
对于新生代中的内存会分为一个Eden和两块Survivor(一个是from,一个是to),比例默认是8:1,在使用时,会在Eden和一块Survivor上面分配内存,清除时会将这两个保留的对象都保存在Survivor中,并且年龄加1(以后提升为老年代),如果超出了Survivor中的限制会用老年代的内存担保。

标记-整理算法

  标记整理算法过程类似于“标记清除”,也是先标记,但是它是让存活的向一端移动,清理掉不是存活的边界的内存。

分代-收集算法

  分代收集算法,并不是什么新思想,只是分不同区域执行,将每个年代的合适的算法采用。如新生代中:适合复制,老年代:适合标记-清理和标记-整理。

HotSopt虚拟机的算法实现

  从可达性算法中找到GC Roots节点找引用链这个操作,首先对于节点的查找很可能会消耗大量的时间,另外可达性分析对执行时间的敏感还体现在GC停顿上(停顿所有线程,防止分析过程还会有不断的引用变化,也叫Stop the world),在号称不会停顿的CMS中(下节会将),枚举根节点时也一样会停顿。

  为了解决这个问题,一般都会采用一组OopMap数据结构达到这个目的,这个数据结构可以很快的判断出来对象内什么偏移量上是什么数据类型计算出来。

  实际上HotSpot没有为每条指令生成OopMap(如果那样做,就会耗费大量的额外空间),只是在特定的位置也就是安全点,记录这些信息。对于安全点:我们如何让所有线程到达安全点呢。这里有两种:

  1.抢占式:不需要线程的执行线程的配合,GC发生时,所有的线程中断,如果有线程没在安全点上,让其恢复然后执行直到安全点。

  2.主动式:不直接对线程操作,仅仅简单地设置一个标志,当线程每次到特殊位置的时候,都会轮询这个标志,如果为真就中断挂起,如果为假就继续执行

  对于Sleep的线程我们会让他进入Safe Region(安全区域),如果这个线程sleep完成了,想离开安全区域,这时会检查GC完成了吗,如果没有,就只有继续等待直至完成。

你可能感兴趣的:(java,虚拟机,算法,内存,对象)