自适应收集器
在第一篇:关于JVM 的垃圾收集(一)中谈到过几种垃圾收集的算法,然而我们的 JVM 启动之后并不要求彻头彻尾的死板的使用一种垃圾收集算法,固定的算法参数。因为某种情况下某些垃圾收集算法工作得更好,而别外一些收集算法在另外的情况下工作得更好,所以自适应的垃圾收集技术应运而生。自适应算法监视堆中的情形,并且对应的调整为合适的垃圾收集技术。或能是换一种垃圾收集算法,或者是调整当前算法参数,或者把堆划分为子堆,同时在不同的子堆中使用不同的算法。
简述火车算法
垃圾收集一般都会停止整个程序的运行来查找和收集垃圾对象,它们可能在程序执行的任意时刻暂停,并且暂停的时间也无法确定。垃圾收集也可能使得程序对事件响应迟钝,无法满足实时系统的要求。如果一种垃圾收集算法可能导致用户可察觉的到的停顿或者使得程序无法适合实时系统的要求,这种算法被称作破坏性。垃圾收集算法的还有一个基本目标是使本质上的破坏性尽可能少,如果可能的话,尽可能消除这种破坏性。
达到(或试图达到) 非破坏性垃圾收集的方法是使用渐进式收集算法。渐进式收集器就是不试图一次性发现并回收所有不可触及的对象,而是每次发现并回收一部分。因为每次只有堆的一部分执行垃圾收集,因此理论上说每次收集会持续更短的时间。保证这个最短时间接近某一个时长,就可以让 Java 虚拟机适合实时环境,也就可以消除用户可察觉的垃圾收集停顿,这可称之为限时渐近时垃圾收集。
渐进式收集器通常是分代收集的,大部分调用中,都是收集堆的一部分。大部分对象都是短命的,利用这一点,分代收集器在年幼子堆中比在年长子堆中更活跃。因为除了最高寿的子堆(成熟对象空间) 外,每个子堆中都可以给定一个最大尺寸,分代收集器大体上可以保证在一个最大时间内渐进地收集所有对象(最高寿的除外)。成熟对象空间无法给定最大尺寸,因为其中的对象不适合时没个去处。
于是针对成熟对象空间提供限定时间的渐时收集,Richard Hudson 和 Eliot Moss 提出了火车算法,目前正用于 Sun 公司的 Hotspot 虚拟机中。该算法详细说明了分代收集的垃圾收集器的成熟对象空间的组织。大体有些车厢、火车、火车站的概念,对于该算法的此处不作进一步说明了。
finalize() 方法
一个 Java 对象可以拥用终结方法:这个方法在垃圾收集器释放对象之前必须运行。但这么一个终结方法的引入并不明智,会使得 JVM 的垃圾收集的工作变得更得杂,所以别用它。
因为,存在终结方法时,垃圾收集器必须在每次在收集时执行一些额外的步骤。首先第一遍扫描时,垃圾收集器检测出不再被引用的对象,然后看那些对象上是否声明了终结方法,有则执行。当执行了所有的终结方法后,垃圾收集器必须再次从根节点或是需要执行终结的对象开始检测不再被引用的对象,这称作第二遍扫描。这个步骤是必要的,因为终结方法可能“复活”了第一遍扫描标记的对象。最后,垃圾收集器才能释放那些在第一遍和第二遍扫描中发现的都没有被引用的对象。
如果第一遍扫描标记不再引用的对象的终结方法运行过了,而后这个对象被自己或其他对象的终结方法复活了,稍后再次被收集时,执行过的终结方法就不能再执行了。同时终结方法何时被执行也是无法预测的。