4中引用(强,软,弱,虚)侧重弱引用

1,强引用,对象有强引用与之关联,即使在内存不足,抛出OutOfMemory错误也不会回收这种对象

2,软引用是用来描述一些有用但并不是必需的对象,java.lang.ref.SoftReference类来表示。
   对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。可以很好地用来解决OOM的问题,适合用来实现缓存:比如网页缓存、图片缓存等。
   软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。

3,弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
在java中,用java.lang.ref.WeakReference类来表示。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,就会被加入到与之关联的引用队列中。
4,虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。 如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。 注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。 弱引用和虚引用的区别是:虚引用总是存在的,只是看存在地方的。而若引用如果没有队列与关联,那么垃圾回收就会没了。如何有关联队列那么两者就一样了。

说说WeakReference弱引用

Java弱引用(WeakReference)的理解与使用

侧重说下弱引用:因为ThreadLocal用到了弱引用,而线程局部变量被广泛的应用在各种框架中。

了解如何定义和使用:

public class Car
{
    private double     price;
    private String    color;
    
    public Car(double price, String color)
    {
        this.price = price;
        this.color = color;
    }
public class WeakReferenceCar extends WeakReference<Car>
{
    public WeakReferenceCar(Car car)
    {
        super(car);
    }
}
Car car = new Car(2000.0, "red");
WeakReferenceCar wrc = new WeakReferenceCar(car);

当gc执行:WeakReferenceCar关联的对象Car被回收掉了。

值得注意的是car本身是有强引用的(xxx=new xxx()):

public static void main(String[] args) {
        
        Car car = new Car(22000,"silver");
        WeakReference<Car> weakCar = new WeakReference<Car>(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;
            }
        }

 即使有 car 引用指向对象, 且 car 是一个strong reference, weakCar指向的对象仍然被回收了.

这是因为java的编译器在发现进入while循环之后, car 已经没有被使用了。

而如果后面有使用是不会被回收的比如下面:

        Car car = new Car(22000,"silver");
        WeakReference<Car> weakCar = new WeakReference<Car>(car);        
        int i=0;        
        while(true){
            System.out.println("here is the strong reference 'car' "+car);
            if(weakCar.get()!=null){
                i++;
                System.out.println("Object is alive for "+i+" loops - "+weakCar);
            }else{
                System.out.println("Object has been collected.");
                break;
            }
        }

总结:

1,一个变量(在方法类创建的)是否被回收,看方法是否执行完,一般都被回收的。
   但是如果赋值给了其他全局变量,那么是不会被回收的。

2,是否是强引用,一般是不会被回收,但是如果后面没有使用,也是会被回收的。

3,是否是弱引用,一般gc执行就会被回收,
但是如果有强引用关联,那么是不会被回收的, 但是出现第2点的情况,也就是后面不被使用了,也是会被回收的
(其实有强引用关联也就当作强引用的情况在处理了)

补充:对于强引用是否需要手动置空?以便让gc回收。

Object c = new Car();
c=null;

其实是不需要的,手动置空对象对于程序员来说, 是一件繁琐且违背自动回收的理念的.  

因为在java中, 对于简单对象, 当调用它的方法执行完毕后, 指向它的引用会被从stack中popup, 所以他就能在下一次GC执行时被回收了

最后一个问题:缓存用哪个引用?

很多人觉得用软引用更好,内存不够再回收。

个人觉得不可以:

据说内存不够时候,清理过程中程序会被挂起,这样很不友好。

而一般启动清理机制,应该是内存使用到达一定程度(应该是可以设置),程序还可以继续执行。

补充:上面的某些说法应该是不确切的:(或者不完整,因为逻辑上不通)

当创建一个对象,用强引用,然后通过传参变成弱引用对象。如果说弱引用对象有被强引用关联那么就是强引用处理,这样弱引用就毫无意义了(不符合逻辑)。

个人理解是:只有非创建时,被强引用,(也就是创建后在别的地方被引用了)才会当作强引用处理。

原文地址:https://www.cnblogs.com/straybirds/p/8314115.html