这次实验是因为在群里和大佬聊天, 当时是问一个弱引用的问题, 有人告诉我把弱引用的变量用get保存起来再去判断, 但是当时觉得这样会有问题, 我问的那个问题我找到原因并解决了[ 参考此文:https://www.jianshu.com/p/2823e17cf9b5 ], 但是这个get保存变量的问题我觉得这样就破坏了弱引用, 所以我想做个试验来测试一下结果
测试代码如下:
public class Car {
}
public class TestWeakReference {
public static void main(String[] args) {
Car car = new Car();
WeakReference<Car> weakCar1 = new WeakReference<>(car);
WeakReference<Car> weakCar2 = new WeakReference<>(new Car());
//weakCar1中的car不能被GC回收,因为在test1方法外有强引用car的指针
// test1(weakCar1);
//虽然方法里用方法参数car创建了弱引用,但是car仍然不能被GC回收,因为在test2方法外有强引用car
// test2(car);
//weakCar2中的car可以被GC回收,因为强引用car只是临时变量
// test1(weakCar2);
//weakCar1中的car不能被GC回收,原因同test1(weakCar1)
// test3(weakCar1);
// //weakCar2中的car能被GC回收,因为:
//1. weakCar2中的car引用在其他作用域里并没有强引用
//2. 虽然在方法里用变量保存了弱引用里的car引用但是后面并没有任何代码去读该变量
// test3(weakCar2);
//weakCar中的car可以被GC回收,因为强引用car在方法内,JVM会做优化
// int i=0;
// while(true){
// if(weakCar1.get()!=null){
// i++;
// System.out.println("Object is alive for "+i+" loops - "+weakCar1);
// }else{
// System.out.println("Object has been collected.");
// break;
// }
// }
//下面是错误的,不应该再去使用强引用,否则GC无法回收弱引用里的car,while循环就会无法停止
// System.out.println(car);
}
private static void test1(WeakReference<Car> weakCar){
int i=0;
while(true){
if(weakCar.get()!=null){
i++;
System.out.println("Object is alive for "+i+" loops - "+weakCar);
}else{
System.out.println("Object has been collected.");
break;
}
}
}
private static void test2(Car car){
WeakReference<Car> weakCar = new WeakReference<>(car);
int i=0;
while(true){
if(weakCar.get()!=null){
i++;
System.out.println("Object is alive for "+i+" loops - "+weakCar);
}else{
System.out.println("Object has been collected.");
break;
}
}
}
private static void test3(WeakReference<Car> weakCar){
Car car = weakCar.get();
int i=0;
while(true){
if(weakCar.get()!=null){
i++;
System.out.println("Object is alive for "+i+" loops - "+weakCar);
}else{
System.out.println("Object has been collected.");
break;
}
}
}
}
代码比较简单, 我也就不逐字逐句的解释了, 我写的注释很详细, 结论就是如果使用弱引用, 那么弱引用中保存的变量不能在其他作用域有强引用才可以在GC时被回收占用的内存, 而且保存到弱引用里以后, 后面也不应该再去直接读取强引用.如在main方法的while循环后面加System.out.println(car);会导致弱引用里的car仍然无法被GC回收, 所以while循环永远不会停止.
比如test1(weakCar1)
这句代码, weakCar1
这个变量中保存的变量car
在test1
作用域以外有强引用, 所以这个时候GC就无法回收car
的内存, test2(car)
这句话也是一样的原因.
而test1(weakCar2)
这句话却可以回收weakCar2
中保存的变量car
, 这是为什么呢? 这是因为weakCar2
中保存的car
是临时变量, 和上面的原因不一样, weakCar2
中保存的car
在代码中并不存在它的强引用, 所以GC可以回收, 也就再次验证了我们的结论.
而test3
这个方法中将弱引用中的变量取出来用一个变量保存起来了, 这时候在while
循环中每次都去判断了这个强引用, 这样做就和弱引用没关系了, 和平时写的代码一样并没有用到弱引用的特性, 所以GC也无法回收car
所占用的内存, 这时候如果在方法里调用弱应用的get()
方法一直都不可能为null.
而在main
方法里的while
循环里的car
也可以被GC回收, 原因是虽然car
有强引用,但是car
和while
在同方法也就是相同的作用域里, 也就像结论里说的, 弱引用保存的变量car
没有在其他作用域里有强引用, 并且后面也没有再去直接读取强引用car
, 所以GC仍然可以回收弱引用里保存的car
网友评论
main方法的最后面摸一下car可破
例如println(car)
test2方法同理