标记垃圾对象算法
堆中存放着几乎所有的对象实例,对堆中垃圾对象进行回收的前提就是判断哪些对象已经成为了垃圾对象(不再被任何途经使用的对象)
引用计数法
给每一个对象添加一个引用计数器
- 当有地方引用他时,计数器加一
- 当引用失效时,计数器减一
- 当计数器为0时,该对象不可能再使用,即为垃圾对象
注意
:该方法实现简单,效率高,但是因为难以解决对象相互循环引用问题,所以目前主流的虚拟机中并没有选择该算法管理内存。
示例相互循环引用:
package com.example.demo;
/**
* @Description
* @Author heiheihei
* @Date 2021/8/29 16:38
*/
public class Test {
//保存其他对象引用
Object obj=null;
public static void main(String[] args) {
//创建对象
Test objA = new Test();
Test objB = new Test();
//引用其他对象
objA.obj=objB;
objB.obj=objA;
//释放自身对象
objA=null;
objB=null;
//造成A对象依旧引用着B对象,而B对象引用着A对象
//如果使用引用计数法实现的内存管理,将会由于计数器未归零,无法回收对象
}
}
可达性分析算法
以“GC Roots"对象为起点,向下寻找引用的对象,被找到的对象被标记为非垃圾对象
,而未被标记的对象都为垃圾对象。
GC Roots 根节点:线程栈的本地变量、静态变量、本地方法栈的变量等等.
补充
常见引用类型
在java中引用类型分为四种类型:强引用、软引用、弱引用、虚引用。
-
强引用:最普通的变量引用
public static User user = new User();
-
软引用:将对象使用SoftReference软引用类型的对象包裹,
正常情况不会进行回收
。- 当GC后
未释放出空间存放新的对象,则将会把软引用的对象回收
。软引用可以用来实现内存敏感的高数缓存
软引用在实际中的实际应用:游览器的后退功能,解决了网页游览结束后是否马上回收问题,防止过多内存溢出,与是否要重新请求问题。
public static SoftReference<User> user = new SoftReference<User>(new User());
- 当GC后
-
弱引用:将对象使用WeakReference弱引用类型的对象包裹,弱引用与没有引用差不多,GC时会直接进行回收。
public static WeakReference<User> user = new WeakReference<User>(new User());
-
虚引用:虚引用又称幽灵引用或幻影引用,是最弱的引用关系,几乎不用。
finalize()方法最终判定对象是否存活
哪怕在可达性分析算法中不可达的对象,也不是
非死不可
,finalize()就是自救的方法。重写finalize()就是如何自救,finalize()是给予对象一次
救命的机会。
流程:
- 第一次标记并进行筛选
筛选对象是否需要执行finalize()方法(是否覆盖finalize()方法)否则对象直接被回收
- 第二次标记
诺在finalize()将自己赋值个某个类变量或对象的成员变量(这些不是垃圾对象),那就会在第二次标记时移除
即将回收对象集合
,如果对象这时候还未逃脱,它就真的被回收了.
注意
:一个对象的finalize()方法只会被执行一次,也就是说通过调用finalize方法自救的机会就只有一次。
判断一个类是无用的类
方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢?
类的回收必须满足3个条件
- 该类的所有实例都已经被回收,就是在java堆中不存在该类的任何实例。
- 加载该类的ClassLoader已经被回收。(防止是刚被加载的类)
- 该类对应的java.lang.Class对象没有被任何地方引用,并且在任何地方通过反射访问该类的方法。
事实证明方法区中的类是很难以回收的,所以在实际中方法区GC后没有明显的变化。