垃圾收集
比较系统应对面试的算法博客详见 https://www.cnblogs.com/gw811/archive/2012/10/19/2730258.html
什么是垃圾收集
-
自动释放不再被程序所使用的对象的过程。
-
垃圾回收器必须能断定哪些对象是不再被引用的,并且能够把它们所占据的堆空间释放出来。在释放不再被引用的对象的过程中,垃圾收集器运行将要被释放的对象的终结方法(finalizer)。
-
垃圾处理器还要处理堆碎块。堆碎块是在正常的程序运行过程中产生的。堆内存的空闲介于活动的对象之间。
为什么要使用垃圾收集
- 可以提高生产率。把用户从释放内存的重担中解放出来。
- 帮助程序保持完整性。程序员不可能因为失误(或者故意)错误释放内存而导致JVM崩溃。
垃圾收集算法
垃圾检测通常通过建立一个根对象的集合,并检查从这些根对象开始的可触及性来实现。如果正在执行的程序可以访问到的根对象和某个对象之间存在引用路径,那么这个对象就是可触及的,也就是“活动”的对象。无法被触及的就认为是垃圾。
根对象来源
- 包含局部变量中的对象引用和栈帧的操作数栈(以及类变量中的对象引用)
- 被加载的类的常量池中的对象引用,比如字符串。
- 传递到本地方法中的,没有被本地方法“释放”的对象引用。
- 潜在:JVM运行时数据区中从垃圾收集器的堆中分配的部分。
区分活动对象和垃圾的两个基本方法
- 引用计数。引用计数垃圾收集器为堆中的每个对象保存一个计数来区分活动对象和垃圾对象。这个计数记录了对那个对象的引用次数。
- 跟踪。跟踪垃圾收集器实际上追踪从根节点开始的引用图。在追踪中遇上的对象以某种方式打上标记(位图/给对象本身标记)。当追踪结束时,没有被打上标记的对象就判定是不可触及的,可以被当作垃圾收集。
引用计数收集器
垃圾收集的早期策略。堆中每一对象都有一引用计数。当一个对象被创建了,并且指向该对象的引用被分配给一个变量,这个对象的引用计数被置为1。当任何其他变量被赋值为对这个变量的引用时,计数加1.当一个对象的引用超过生存期或者被设置为一个新的值时,对象的引用计数减1.任何引用计数为0的对象可以被当作做垃圾收集。当一个对象被当作垃圾收集时,它引用的任何对象计数值减1。
好处
引用计数收集器可以很快地执行,交织在程序运行中。这个特性对于程序不能被长时间打断的实时环境很有利。
坏处
- 引用计数无法检测出循环(即两个或者更多对象的互相引用)。
- 每次引用计数的增加或者减少都带来额外开销。
跟踪收集器
基本的追踪算法被称作“标记并清除”。这个名字指出两个收集的阶段。标记阶段,垃圾收集器遍历引用树,标记每一个遇到的对象。清除阶段,未被标记的对象被释放了,使用的内存被返回到正在执行的程序。在JVM中,清除步骤必须包括对象的终结。
压缩收集器
标记并清除收集器通常使用的两种策略是压缩和拷贝。这两种方法都是快速地移动对象来减少堆碎块。压缩收集器把活动的对象越过空闲区滑动到堆的一端,这个过程中,堆的另一端出现一个大的连续空闲区,所有被移动的对象的引用也被更新,指向新的位置。
拷贝收集器
拷贝垃圾收集器把所有的活动对象移动到一个新的区域。在拷贝的过程中,它们被紧挨着布置,所以可以消除原本它们在旧区域的空隙。原本的区域被认为都是空闲区。这种方法的好处是对象可以再从根对象开始的遍历过程中随着发现而被拷贝,不再有标记和清除的区分。对象被快速拷贝到新区域,同时转向指针仍留在原来的位置,转向指针可以让垃圾收集器发现已经被转移的对象的引用。然后垃圾收集器可以把这些引用设置为转向指针的值,所以他们现在指向对象的新位置。
一般的拷贝收集器算法被称为“停止并拷贝”。在这个方案中,堆被分为两个区域,任何时候都只使用其中的一个区域,对象在同一个区域中分配,直到这个区域被耗尽,此时,程序执行被终止,堆被遍历,遍历时遇到的活动对象被拷贝到另外一个区域,当停滞和拷贝过程结束时,程序恢复执行。内存将从新的堆区域中分配,然后重复。z代价就是对于指定大小的堆来说需要两倍大小的内存,因为任何时候都只能使用其中的一半。
按代收集的收集器
简单的停止并拷贝收集器的缺点是,每一次收集时,所有活动对象都必须被拷贝。
大多程序的共性如下:
- 大多数程序创建的大部分对象都具有很短的生命期。
- 大多数程序都创建一些具有非常长生命周期的对象。
按代收集的收集器通过把对象按照寿命来分组解决这个效率低下的问题,更多收集那些短暂出现的年幼对象。在这种方法中,堆被划分为两个或者更多的子堆,每一个子堆为一代对象服务。如果一年幼对象经历多次收集仍存活,那么将被转移到另一个子堆中。年龄高的没有年幼的那么频繁。
自适应收集器
自适应算法监视堆中情形,并对应地调整为合适的垃圾收集技术。
火车算法
不对系统实时性造成影响的算法是渐进式收集算法。不试图一次性发现并收集所有垃圾。
火车算法在大多数情况下可以保证一次垃圾收集所耗时间在一定限度之内,因为一次垃圾回收只收集一个车厢,而车厢的大小是有限度的。