GC要解决三个主要的问题:
- 哪些内存需要回收?
- 什么时候回收?
- 如何回收?
哪些内存需要回收?
最简单的是引用计数(reference count),缺陷是无法解决循环引用。于是更快点的算法是可达性分析(reachable analysis)。
什么时候回收?
至少要经历两次标记过程:
- 在进行可达性分析后,发现没有与GC roots相连接的引用链时,会被第一次标记并进行一次筛选——是否有必要执行finalize()。
- 对象没有finalize()方法或者被虚拟机执行过,视为“没必要执行”
- 有必要执行finalize(),被放置于F-Queue队列中,并在稍后由(虚拟机自动建立的、优先级低的)Finalizer线程去“执行”(触发相应方法,但并不会等待它完成)。
- 之后GC将对F-Queue中对象进行第二次小规模的标记。
如何回收?
- Mark-Sweep(标记-清除):(缺陷:会造成大量的内存碎片。)
- Copy:内存一分为二,每次只使用其中的一半。清理时,将存活对象拷贝到未使用的另一半,再将已用的这一半清理掉。(缺陷:将内存缩小为原来的一半,在存活对象较多时效率很低。所以在新生代区域会使用这种算法,一大块Eden和两块Survivor区域。每次使用Eden和其中一块Survivor区域。)
- Mark-Compact(标记-整理):让所有存活的对象,往一端移动,适用于存货对象较多的区域,如老生代。
- 分代收集:综合了以上所有方法,对不同的generation区域使用不同的算法。
参考文献: