对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。
优点:实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
缺点:a.它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。b.每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。c.引用计数器还有一个严重问题,即无法处理循环引用的情况。这是一条致命的缺陷,导致在Java的垃圾回收器中没有使用这类标记方法。
循环引用
当Obj1对象的指针断开的时候,内部的引用形成一个循环,这就是循环引用,从而造成内存泄漏。
概述
可达性分析算法:也可称为根搜索算法、追踪性垃圾收集(Tracing Garbage Collection)算法
相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生。
基本思路
可达性分析算法是以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain)
如果目标对象没有任何引用链,则是不可达的,就意味着该对象已经死亡,可以标记为垃圾对象。
在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。
GC Roots可以是哪些?虚拟机栈引用的对象
比如:各个线程被调用的方法中使用到的参数、局部变量等。
本地方法栈内JNI(通常说的本地方法)引用的对象,方法区中类静态属性引用的对象
比如:Java类的引用类型静态变量
方法区中常量引用的对象
比如:字符串常量池(String Table)里的引用
所有被同步锁synchronized持有的对象
Java虚拟机内部的引用
基本数据类型对应的Class对象,一些常驻的异常对象(如NullPointerException、OutOfMemoryError),系统类加载器。
反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
当成功区分出内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用空间为新对象分配内存。目前在JVM中比较常见的三种垃圾收集算法是:
标记-清除算法(Mark-Sweep)
复制算法(Copying)
标记-整理算法(Mark-Compact)
清除阶段:标记-清除算法标记清除算法是一种非常基础和常见的垃圾收集算法,该算法被 J.McCarthy等人在1960年提出并应用于Lisp语言。
执行过程
当堆中的有效内存空间被耗尽的时候,就会停止整个程序(也被称为stop the world),然后进行两项工作,第一项是标记,第二项则是清除。
标记:Collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
标记的是引用的对象,不是垃圾!!