java中的弱引用 WeakReference
前言
最近在看ThreadLoca的实现机制,发现ThreadLocalMap的key是弱引用对象,下面针对弱引用做了一些简单的测试。
jvm GC的可达性分析算法
理解弱引用,需要先简单了解些jvm gc的一种方法:可达性分析算法
可达性分析法定义了一系列称为"GC Roots"的对象作为起始点,从这个起点开始向下搜索,每一条可达路径称为引用链,当一个对象没有任意一条引用链可以到达"GC Roots"时,那么就对这个对象进行第一次"可回收"标记。
那么什么是GC Root呢? 可以理解为由堆外指向堆内的引用。
那么都有哪些对象可以作为GC Roots呢?包括如下几种
- 代码中某一方法中的局部变量
- 类变量(静态变量)
- 常量
- 本地方法栈中引用的对象
- 已启动且未停止的线程
下面用代码来简单说明下:
public class Man {
private static Book book = new Book("HarryPotter");
private String name;
public Man(String name) {
this.name = name;
}
private static void main(String[] args){
Man badGuy = new Man("Bad Guy");
}
}
class Book{
private String name;
public Book(String name) {
this.name = name;
}
}
GC Roots:
当main方法运行完之后,new Man(“Bad Guy”)对象不可由GC ROOT到达,所以会被gc。
java中的引用类型
强引用
通过关键字new的对象就是强引用对象,强引用指向的对象任何时候都不会被回收,宁愿OOM也不会回收。
软引用
如果一个对象持有软引用,那么当JVM堆空间不足时,会被回收。
一个类的软引用可以通过java.lang.ref.SoftReference持有。
弱引用
如果一个对象持有弱引用,那么在GC时,只要发现弱引用对象,就会被回收。
一个类的弱引用可以通过java.lang.ref.WeakReference持有。
虚引用
几乎和没有一样,随时可以被回收。
通过PhantomReference持有。
测试代码
public class Student {
private String name = "initName";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args){
Student student = new Student();
WeakReference<Student> studentWeakReference = new WeakReference<>(student);
System.out.println("gc 前 :"+studentWeakReference.get());
student = null;
System.gc();
System.out.println("gc 后 :"+studentWeakReference.get());
}
}
gc前,new Student()可以从studentReference和student到达,当student=null执行后,在后面进行gc的时候,只有弱引用studentReference可到达new Student(),所以new Student()会被回收,程序运行的结果如下: