判断哪些对象是垃圾
-
引用计数器算法(最早使用的算法)
当我们在内存中创建一个对象时,会为他添加一个引用计数器,同时将引用计数器加1,当有新的引用器引用到子对象时,引用计数器再加1,当其中的一个引用销毁时,引用计数器减1,当引用计数器减为0 时,标志着此对象为垃圾对象,可被回收。
存在问题:
如图,当对象A引用对象B时,对象B的计数器加1,对象B再引用对象A,对象A的计数器也加1,但是并没有其他路径指向他们,此时的对象A和对象B已经成为垃圾对象,但由于二者的计数器都不为0,引用计数算法无法回收他们的内存。为了解决这个问题,可达性算法诞生了。
-
可达性算法(根搜索算法)
通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的,即为垃圾对象
此处的obj4、obj6、obj7、obj8都为不可达对象,即垃圾对象
引用的类型
-
强引用
Object obj = new Object();
-
弱引用(不会阻碍内存的回收)
需要被 WeakReference 类包装
WeakReference<Object> wf = new WeakReference<Object>(obj);
-
软引用
需要被 SoftReference 类 包装
-
虚引用
需要被 PhantomReference 类 包装
最常用到的是强引用和弱引用
垃圾回收算法
- 标记-清除算法
如图,从根节点引用A,A引用C,则B为不可达点,进行扫描,进入标记阶段,标记B,此时B为垃圾对象,接下来进入清除阶段,扫描整个空间并清除未标记的对象
缺点就是容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。
- 复制算法
如图,从根节点引用A,将A放置在另一块空闲的内存中,B为不可达点,跳过,A引用C,将A放置在另一块空闲的内存中,当遍历完成后,将原来的内存清空,只保留了新的内存。
优点:对象少时,效率极高
缺点:需要一块内存
- 标记-整理算法
如图,进行全局扫描,标记出可回收的对象,进入清除阶段,将可回收对象清除,将所有的存活对象向左端空闲处移动并更新对应空闲指针
触发回收
- Java虚拟机无法再为新的对象分配内存空间
- 手动调用System.gc()方法(强烈不推荐)
- 低优先级的GC线程,被运行时就会执行GC
网友评论