垃圾收集是Java语言非常显著的特点,不像C语言那样,老是要考虑什么数字的越界什么的。什么是垃圾(garbage)呢?“An object is considered garbage when it can no longer be reached from any pointer in the running program.”首先要了解一下内存的分配:
- 静态分配( Static Allocation ):静态变量和全局变量的分配形式。
- 自动分配( Automatic Allocation ):存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中。在栈中为局部变量分配内存的方法。栈中的内存可以随着代码块退出时的出栈操作被自动释放。
- 动态分配( Dynamic Allocation ):在堆中动态分配内存空间,存放用new产生的数据。
所以垃圾收集针对的是堆里面的对象。那首先想到的最简单的算法就是引用计数 (Reference Counting),对每个对象保存一个引用计数,如果计数为零,那就可以删除了。但是缺点是,新的对象生成,就需要更新相关的计数;更重要的是无法删除循环引用(比如两个对象彼此引用)。
其它的方法都涉及到一个概念root set,简单的讲就是栈里面的对象引用和堆里面的对象的集合。从这些对象开始就可以一级一级的trace到所有live的对象了。"Any object referred to by a root is reachable and is therefore a live object. Additionally, any objects referred to by a live object are also reachable. "【3】基于这个的算法有:
- 标记-清除(Mark-Sweep)算法:首先标记出live的对象,那些没有被标记的就可以被收集了。
- 复制(Copying)算法:将内存分成两部分,收集的时候,live的对象从一部分被移动到另一个部分,如此往复。
- 分代收集(Generational Collecting)算法:这个也是Java使用的算法,基于统计结果并综合了前面算法优点。
Java的垃圾收集
首先是一个观察:infant mortality。大意就是很多对象的生存时间很短,很少的对象会存活很久。因此堆被分成了几部分,分别存放不同寿命的对象。
注:引用自参考【4】
新对象先放到Young里面,这里面的对象会经常被收集,如果还存活下来就放到survivor里面,还能存活下来就放到Tenured里面。当年轻对象空间快慢了,开始minor collection。当tenured generation需要收集的时候,叫major collection。这个的频率要低同时也更慢。
参考:
【1】http://developer.51cto.com/art/201009/225071.htm
【2】http://blog.csdn.net/javafuns/archive/2007/09/04/1771535.aspx
【3】http://www.artima.com/insidejvm/ed2/gcP.html
【4】http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html