什么是需要回收的垃圾
垃圾是指在运行程序中没有任何指针指向的对象,该对象不会再被程序利用,但是又占据着内存空间直至程序结束。
GC的原因
- 释放掉没用的对象
- 清除内存中的碎片
GC作用的区域
GC作用在方法区和堆中,其中堆是垃圾收集器的工作重心。在堆中,GC频繁收集新生代区,较少收集老年代区,基本不动永久代。
如何判断对象是否存活
主要有两种方法:引用计数器法和可达性分析法
引用计数器法:
每个对象维护一个整形的引用计数器属性。当有别的对象引用该对象时,该对象引用计数器加一;当引用失效时,计数器减一。则当该对象的引用计数器为0时,表示该对象可被回收。
可达性分析算法
根据GC Roots(一组必须活跃的引用)为起始点,按照从上而下的方式搜索所有被根对象集合所连接的目标对象是否可达。由根对象到所有可达对象经过的路径被称为引用链。
若目标对象和根对象之间没有引用链相连,则是不可达的,则会被标记为垃圾对象。
finalization机制
finalization()是Object类中的方法,所有的类都继承于Object,因此每个对象都可调用。一个finalization()方法只会被调用一次。
垃圾回收某一个对象之前,总会先调用这个对象的finalization()方法,它允许在子类中被重写,用于在对象回收时进行资源的释放。
判断对象是否可回收的过程
- 如果某个对象道GC Roots之间没有引用链,则进行第一次标记
- 进行筛选,判断此对象有没有必要执行finalization()方法
- 如果finalization()方法没有被重写,或者该方法已经被调用过,则对象被判定为不可触及
- 如果对象重写了finalization()方法,且还没有被执行过。那么该对象将会被插入到一个队列F-Queue中
- finalization()方法是对象逃脱死亡的最后机会,稍后GC会对F-Queue队列中的对象进行第二次标记。如果该对象在finalization()方法中与引用链中任何一个对象建立了联系,那么该对象将会被移出即将被回收集合。之后,对象会再次出现没有引用存在的情况。这样情况下,对象直接变为不可触及状态
所有不可触及对象将被回收。
垃圾清理算法
标记清理算法
- 标记:从根节点进行遍历,标记所有的可达对象
- 清理:对所有的不可达对象进行回收操作
缺点:容易产生大量的内存碎片
注意:这里的清楚并不是真的置空置零,而是把被清除对象的地址保存在空闲的地址列表中。有新对象需要加载时,直接进行覆盖。
复制算法
流程:将内存空间分为两块,每次只使用其中一块。在垃圾回收时将正在使用的一块中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的全部对象,交换两个对象角色,完成垃圾回收。
优点:运行高效,实现简单
缺点:需要两倍内存空间
标记压缩算法
流程:
- 标记:从根节点进行遍历,标记所有的可达对象
- 整理:将所有的存活对象压缩到内存的一端,按顺序摆放
- 清除:清理边界外所有空间
优点:不会造成大量内存碎片,也无需付出两倍内存空间的代价
缺点:效率低于复制算法
增量收集算法
为防止GC时间过长,其基本思想是每次只收集小片区域的内存,然后切换到应用程序进程,依次反复,直至垃圾收集完毕
底层依然是标记清除算法或者复制算法。
分区算法
将堆内存分为几个小区间,每次GC只回收若干个小区间,而不是整个堆空间。每个小区间都独立使用,独立回收。