在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(“死去”即不可能再被任何途径使用的对象)了。
根据什么判断对象是否可以被GC掉呢
1.引用计数算法
在网上讲述大多判断对象是否还存活的方法为: 在对象中添加一个引用计数器,引用+1。引用失效则-1。任何时刻计数器为0的对象便不能被使用了
当然引用计数算法在使用上面,判断效率还是很高的。总之是个不错的算法。比如微软的COM技术、使用ActionScript 3的FlashPlayer、Python语言以及在游戏脚本领域得到许多应用的Squirrel中都使用
了引用计数算法进行内存管理。 但是!在JAVA之中却没有使用引用技术算法来进行管理内存。因为这个算法在许多情况下出现的问题需要进行考虑,比如两个对对象之间的循环引用!
/** * @Author: Liy * @Date: 2020/5/20 10:17 * @Description: 引用计数算法回收引用 **/ public class ReferenceCountingGC { public Object instance = null; private static final int _1MB = 1024 * 1024; /** * jie个成员变量用来占点内存 */ private byte[] bigSize = new byte[2 * _1MB]; public static void testGC() { ReferenceCountingGC objA = new ReferenceCountingGC(); ReferenceCountingGC objB = new ReferenceCountingGC(); objA.instance = objB; objB.instance = objA; objA = null; objB = null; // 此处会发生GC,引用计数算法是否能回收objA And objB System.gc(); } public static void main(String[] args) { testGC(); } }
此处的运行结果日志中便会 出现,“4603K->210K”。虽然两个对象之间在互相引用,但是JVM并没有放弃回收它们。从而可想JVM并不是通过引用技术算法来回收对象的
2.可达性分析算法
JAVA、C#便是通过可达性算法来判断对象是否还存活的。通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下进行搜索,搜索过程所走过的路径称为“引用链”,如
果某个对象到GCRoots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。
上图:
在Java技术体系里面,固定可作为GC Roots的对象包括以下几种:
1.在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等
2.·在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量
3.·在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用
4.·在本地方法栈中JNI(即通常所说的Native方法)引用的对象
5.·Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器
6.·所有被同步锁(synchronized关键字)持有的对象
7.·反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
无论我们是用引用还是可达性,判断对象是否还存活都和“引用”有关系