垃圾回收(garbage collection)介绍

来源:互联网 发布:淘宝的伞黑胶都在外面 编辑:程序博客网 时间:2024/05/20 22:02

垃圾回收用来实现内存的自动管理(automatic management),区别于人工管理(manual management)。人工管理内存容易出现的问题:
1)悬垂指针,dangling pointer
2)重复回收,Double free
3)内存泄露,memory leak

历史
垃圾回收的概念及技术由John McCarthy于1959年发明,应用于List语言中。1959年,计算机科学应该还处于探索、萌芽阶段,但这位大神已经发明了垃圾回收,大神就是大神。

策略
目前的垃圾回收策略有两种:
1)引用技术 reference counging
思路:给每个对象增加一个引用计数器。每增加一个队对象的引用,计数器增加;较少引用,计数器减少;当计数器是0时,表示对象可以回收。

这种方式实现简单,速度快,回收代码和程序代码执行同步;最大的问题是不能解决循环引用问题(cyclic reference)。

2)对象追中 object tracing
思路:保存系统中所有已分配的对象,一些对象被称为根(roots objects)。所有跟对象及从跟对象可达(reach)的对象被称为活跃对象(active),剩余的对象就是垃圾对象,可以进行回收。
实现较复杂,回收时机和运行时间不可控(回收代码和程序代码分开运行,回收代码会阻塞程序代码的运行),但可以解决循环引用问题。

每种策略都有系统采用:
采用引用计数的有:ios,python,COM,C++库(auto_ptr等)
采用对象追踪的有:Java, .Net, lisp等

算法
主要介绍基于对象追踪的算法。
标记-清除法,mark-sweep
这个应该是由John McCarthy发明的。将垃圾回收分为两个阶段:
标记阶段:找出所有active对象,从跟对象开始遍历。所有active对象通过一个标志位表示。
清除阶段:遍历所有对象,如果该对象不是active的,回收,释放空间。
清除后的内存存在碎片问题(fragmentation)。

复制算法,copying
也叫Cheney's algorithm, 由C.J. Cheney发明,大约在1970年。思路将内存分成大小相同的2个区:当一个区满了后,对这个区执行垃圾回收。先执行标记阶段找出所有活跃的对象,然后将所有活跃对象复制到另外一个内存区,当前内存区可以被整个回收。
这种方法解决了内存碎片问题,但是引入一个新问题,内存利用率只有一半。

分代算法,generational
没有找到具体的发明人。
将内存分成不同的区,每个区存放不同特点的对象,如按照对象的生命周期长短来划分。每个区可以采用不同的方法进行回收。在目前的JVM实现中,都是采用这种分带的算法进行垃圾回收。

Oracle JVM中的分代:
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

上述3个算法构成了整个垃圾回收的核心,当前的所有算法都是基于上述三种方法产生。这三种方法本身都不是很复杂,但第一个想到这些方法的人还是非常伟大的。

衍生算法
标记整理,mark-sweep-compact(也叫mark-compact)
这种方法是mark-sweep和copy算法的结合。先执行标记阶段找出所有活跃的对象,然后将所有活跃对象向内存区的起始点移动(rellocate),所有对象连续防止。最后一个活跃对象的后面的所有内存空间可以一次性释放,这种方法即解决了内存碎片问题,又解决了内存利用率的问题。目前JVM中广泛采用。

Oracle JVM中的GC
主要采用了3种算法:分代,拷贝和标记整理。
对young(青年代)的回收,采用拷贝算法。注意的是,内存并没有分成2个大小相同的区,而是不等的两个区eden和survivor,具体比例可以通过JVM参数设定。这个设计的依据是:绝大多数对象在GC后都会被回收,只有少量存活,所有survivor不必和eden一样大。对young的回收在JVM中叫做minor GC(or young GC),因为空间较小,速度会比较快,也会比较频繁。

对tenured(老年代)的回收,采用标记整理(mark-sweep-compact)算法。回收过程中需要对象的移动过程,同时tenured的空间也会比较大,回收时间会比较长。jvm中对整个heap(包括young和tenured,perm永久区不属于heap)的回收叫做full gc。minor GC可能会触发full gc的运行。

按GC算法的并发能力分:
串行收集 serial collector
单线程执行,效率高,但是不支持多核。

并行收集 parallel collector
多线程执行,支持多核,在多核处理器上性能高。

按与程序代码的运行关系:
stop the world
执行GC时,程序代码不能执行。

Concurrent
GC可以和程序代码同时执行,但不是完全的并行,也需要停止程序代码,但停止时间比较短。目前能支持并发的只有一种即Concurrent Mark-Sweep (CMS) Collector。

JVM中的GC可以按照上方方法归类,每个GC都可以从上述几个维度划分。分代算法,是否并行,是否可并发执行等。


0 0
原创粉丝点击