引用计数
每个对象添加一个计数器,对象引用时,计数器+1,失效时-1,根据是否为0判断(无法解决循环引用问题)
可达性分析算法
选择根节点GC root进行搜索,与GC root没有可达路径的对象则进行清除,解决了循环调用问题。
分代收集理论
弱分代(朝夕生灭)
强分代(熬过越多次垃圾收集过程的对象越难以消亡)
跨代引用(存在相互引用关系的两个对象,倾向于同时生存或者同时消亡,随着年龄增长晋升到老年代,跨代引用消除 [标记老年代中存在跨代引用的内存,Minor GC时只需扫描这一小块内存)–相对于同代引用仅占少数
标记-清除算法
标记部分对象,同意回收或者使标记对象存活(造成空间碎片化)
标记-复制算法
将内存分为若干块,每次一块内存用完则将其中存活对象复制到另一块上,再将原来的内存块全部清除(运行高效,但是将可用内存缩小一半,空间浪费大 ------复制算法在对象存活率较高时需要较多复制操作,降低效率,并且需要进行分配担保,防止原块上对象100%存活的极端情况)
标记-整理算法
将存活对象都向内存空间的一端移动,然后清理掉边界以外的内存(移动时需要全程暂停程序—“Stop the world”)
和稀泥
多数时间采用标记-清除算法,空间碎片化程度大时执行一次标记-整理算法。
- [ ]
在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
在老年代中,因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理算法或者标记-整理算法来进行回收。
安全点
程序运行到达安全点才能进行暂停回收对象。为了让线程都跑到安全点暂停:
1. 抢先式中断
垃圾收集发生时,暂停全部线程,再开启未到达安全点的线程,直至到达安全点
3. 主动式中断
中断线程时,各个线程主动轮询一个标志位,一旦发现中断标志为真则在最近安全点主动中断挂起。
安全区域(拉伸的安全点)
线程进入安全区域时主动等待,直至虚拟机完成根节点枚举。
记忆集与卡表
记录精度
- 字长精度
精确到一个机器字长(该字包涵跨代指针) - 对象精度
精确到一个对象(该对象包涵跨代指针) - 卡精度(卡表)
内存块分为卡页(HotSpot中为2的九次方幂大小字节数)
卡页内存在跨代指针则将对应卡表数组元素置1(元素变脏)垃圾收集时只需要扫描变脏的卡页,将其加入GC Roots
写屏障
类似spring中AOP切面,防止活动对象漏掉未被压入标记栈
例
(A所有子对象遍历完后A出栈,此时B又取消对C的连接,导致C对象被遗漏,使用写屏障防止活动对象被遗漏
write_barrier(obj, field, newobj){
if(newobj.mark == FALSE)
newobj.mark = TRUE
push(newobj, $mark_stack)
*field = newobj
}