本文中分享两种GC确定回收的算法
引用计数算法以及可达性分析算法
引用计数算法:简单来说引用计数算法就是当前内存地址存在多少个对象引用了这一块地址,使用一个标识来记录引用的个数,如果引用大于0则标识当前内存地址被其他的对象引用着,那么GC将不会做回收处理,反之GC将会认为该引用可以被回收。
这里举个例子说明:
//new出一个新的Object对象
Object o1 = new Object();
因为新new出来的对象会指向对象的引用地址,那么o1会持有这个引用,所以新的对象引用的引用数是1。
//将o1的引用断开
o1 = null ;
将o1设置成null时,引用地址与o1引用链接被断开,所以引用地址的引用数从1 -> 0,当引用数量为0,那么引用地址会被GC认定为垃圾将被回收。
但是引用计数算法存在缺点,当对象互相引用容易出现计算器永不为0
举个例子来说明
//new出一个新的Object对象
Object o1 = new Object();
此时的引用地址只被o1引用所以引用数为1
//创建一个对象o2
Object o2 ;
//将o1的引用地址赋值给o2
o2 = o1 ;
此时o2再次引用了o1的引用地址,所以医用地址做+1操作,所以当前的引用地址数量从1变为2
//将o1的引用断开
o1 = null ;
当前o1与引用地址链接被断开,引用地址的引用数量从2变为1,因为创建出来的引用地址仍然被o2引用,所以引用地址无法被GC认定为可以回收的垃圾内存,当这种现象不断发生却没有做处理的时候,这样就会引发OOM。
可达性分析算法:算法的基本思路就是从一个起点(GC Root)树形结构的往下面走,判断每一个节点是否还持有引用链,倘若引用链仍然被持有那么对象将不会被GC回收,如果引用链断开也就是说在树形结构往下查找判断时检测引用链断开了,那么GC将会可以回收对象。
可达性分析算法简单示意图中可以看到,从GC Root作为起点并与ObJA等对象(也就是图中蓝色背景部分)持有引用链,但是图中的ObJD、ObJE、ObJF(也就是图中的黄色背景部分)是不在存在引用链的,也就是说在已GC Root为起点在检索过程中会发现这些对象不持有引用链那么这些对象将会面临被回收的可能。
在Java中可以作为GC Root的对象有以下几种
- 虚拟机栈运行时中的引用
- 常量
- 静态属性
- JNI引用对象
为什么说是会面临被回收的可能?
因为在GC回收扫描时需要经过两次扫描才会回收对象,第一次GC回收扫描时发现对象可以被回收,GC会对对象做一次标记操作,等到GC第二次被回收时对象才会被回收,所以可以在第一次标记到回收期间做操作将对象重新添加到引用链上,通过Object中的finalize()方法实现该动作,以下举个例子说明。
static App a;
@Override
protected void finalize() throws Throwable{
super.finalize();
//将对象a重新添加引用链
a=this;
}
以上当对象被GC标记为要回收的对象后,可以通过finalize()内部再次将对象添加到引用链上,所以这样就实现了对象被标记为回收后重新被拉活。
下一篇 了解下四种引用类型同时了解下不同引用类型与GC回收的关系
Android 性能优化-内存篇(3) - 简书