java4种对象引用级别

参考文档:https://www.cnblogs.com/gudi/p/6403953.html

参考文档:https://www.cnblogs.com/skywang12345/p/3154474.html

从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。细分的准则是体现在被GC回收的优先级上,这四种级别由高到低依次为: 强引用  >  软引用  >  弱引用  >  虚引用

强引用StrongReference

如果一个对象具有强引用,那么垃圾回收器绝不会回收它。就算内存空间不足,jvm宁可抛出OutOfMemoryError使程序异常终止,也不会通过回收具有强引用的对象来解决内存不足的问题。Car car= new Car(); // 这就是强引用。通常我们通过new来创建一个新对象时返回的引用就是一个强引用,若一个对象通过一系列强引用可到达,它就是强可达的(strongly reachable),那么它就不被回收。如果不使用时,要通过如下方式来弱化引用,car = null;//help gc 显式地设置car为null,或超出对象的生命周期范围,则gc认为该对象不存在引用,这时就可以回收这个对象。具体什么时候收集这要取决于gc的算法。

使用:    

public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
//elementData中存储其实是对象的引用,也就是地址,存在于栈中,真正的对象存在于堆中。如果不手动置为null,那么jvm就不会回收它们
            elementData[i] = null;  
            size = 0;
        }
}

软引用SoftReference:对内存敏感 https://www.cnblogs.com/mfrank/p/9781216.html#autoid-0-2-0

在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

软可达对象:如果一个对象与GC Roots之间不存在强引用,但是存在软引用,则称这个对象为软可达(soft reachable)对象

实现内存敏感的告诉缓存、浏览器的后腿按钮:在垃圾回收器没有回收它的时候,软可达对象就像强可达对象一样,可以被程序正常访问和使用,但是需要通过软引用对象间接访问,需要的话也能重新使用强引用将其关联。所以软引用适合用来做内存敏感的高速缓存。

使用:

String s = new String("Frank");     // 创建强引用与String对象关联,现在该String对象为强可达状态

SoftReference softRef = new SoftReference(s);     // 再创建一个软引用关联该对象

s = null;        // 消除强引用,现在只剩下软引用与其关联,该String对象为软可达状态

s = softRef.get();   // 重新关联上强引用,如果在softRef指向的对象被回收前,用强引用指向该对象,那这个对象又会变成强可达,gc就不会回收字符串对象了

变量s持有对字符串对象的强引用,而softRef持有对该对象的软引用,所以当执行s = null后,字符串对象就只剩下软引用了,这时如果因为内存不足发生Full GC,就会把这个字符串对象回收掉。

public class TestA {

    static class OOMClass{

        private int[] oom = new int[1024 * 100]; // 100KB

    }

//修改vm参数,以便更好模拟gc回收:-verbose:gc -Xms4m -Xmx4m -Xmn2m

    public static void main(String[] args) throws InterruptedException {

        ReferenceQueue queue = new ReferenceQueue<>();

        List list = new ArrayList<>();

        while(true){

            for (int i = 0; i < 100; i++) {

                list.add(new SoftReference(new OOMClass(), queue));

            }

            Thread.sleep(500);

        }

    }

}

 

SoftReference对象是用来保存软引用的,但它同时也是一个Java对象。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但SoftReference对象本身并不是null,而此时这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。

ReferenceQueue就是用来保存这些需要被清理的引用对象的。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中

软引用的特点:

软引用弱于强引用

软引用指向的对象会在内存不足时被垃圾回收清理掉

JVM会优先回收长时间闲置不用的软引用对象,对那些刚刚构建的或刚刚使用过的软引用对象会尽可能保留

软引用可以有效的解决OOM问题

软引用适合用作非必须大对象的缓存

 

 

弱引用WeakReference:WeakHashMap https://www.cnblogs.com/mfrank/p/9829993.html

描述非必需对象。被弱引用关联的对象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。

当一个对象仅仅被weak reference(弱引用)指向, 而没有任何其他strong reference(强引用)指向的时候, 如果这时GC运行, 那么这个对象就会被回收,不论当前的内存空间是否足够,这个对象都会被回收。

软引用和弱引用的区别在于,若一个对象是弱引用可达,无论当前内存是否充足它都会被回收,而软引用可达的对象在内存不充足时才会被回收,因此软引用要比弱引用“强”一些。只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于gc是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。这个引用不会在对象的垃圾回收判断中产生任何附加的影响

public class WeakReference extends Reference {

    public WeakReference(T referent) {

        super(referent);

    }

//如果弱引用所引用的对象被垃圾回收,JVM就会把这个弱引用加入到与之关联的引用队列中。

    public WeakReference(T referent, ReferenceQueue q) {

        super(referent, q);

    }

}

使用:eg1

Car car = new Car(); //创建一个强引用对象

WeakReference weakReference = new WeakReference<>(car); //创建一个弱引用对象,指向强引用对象car

int i = 0;

while (weakReference.get() != null) {   //weakReference指向的对象被回收时,退出while,被gc的时间不确定

i++;

System.out.println("Object is alive for " + i + " loops - " + weakReference);

}

System.out.println("Object has been collected.");

eg2: 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,jvm就会把这个弱引用加入到与之关联的引用队列中。

//创建一个引用队列
    ReferenceQueue queue = new ReferenceQueue();
// 创建弱引用,此时状态为Active,并且Reference.pending为空,当前Reference.queue = 上面创建的queue,并且next=null
    WeakReference reference = new WeakReference(new Object(), queue); //没有任何引用指向new Object(),下次gc时被回收
    System.out.println(reference);



Object ref = new Object(); 

WeakReference reference = new WeakReference(ref, queue);

ref = null;//ref指向new Object(),如果在gc前不手动ref=null,reference就无法enquene,会一直处于wait状态


//help gc 当GC执行后,由于是弱引用,所以回收该object对象,并且置于pending上,此时reference的状态为PENDING
    System.gc();

    /* ReferenceHandler从pending中取下该元素,并且将该元素放入到queue中,此时Reference状态为ENQUEUED,Reference.queue = ReferenceENQUEUED */


    /* 当从queue里面取出该元素,则变为INACTIVE,Reference.queue = Reference.NULL */
    Reference reference1 = null;
    try {
        reference1 = queue.remove();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(reference1);

弱引用与软引用的区别在于:

只具有弱引用的对象拥有更短暂的生命周期。

被垃圾回收器回收的时机不一样,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。而被软引用关联的对象只有在内存不足时才会被回收。

弱引用不会影响GC,而软引用会一定程度上对GC造成影响。

那么什么时候用SoftReference,什么时候用WeakReference呢?

如果缓存的对象是比较大的对象,使用频率相对较高的对象,那么使用SoftReference会更好,因为这样能让缓存对象有更长的生命周期。

如果缓存对象都是比较小的对象,使用频率一般或者相对较低,那么使用WeakReference会更合适。

当然,如果实在不知道选哪个,一般而言,用作缓存时使用WeakHashMap都不会有太大问题。

 

弱引用是比软引用更弱的引用类型

弱引用不能延长对象的生命周期,一旦对象只剩下弱引用,它就随时可能会被回收

可以通过弱引用获取对象的强引用

弱引用适合用作缓存

 

虚引用PhantomReferencehttps://www.cnblogs.com/mfrank/p/9837070.html

      虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

public class PhantomReference extends Reference {

    public T get() {

        return null;

    }

    public PhantomReference(T referent, ReferenceQueue q) {

        super(referent, q);

    }

}

使用虚引用的目的就是为了得知对象被GC的时机,所以可以利用虚引用来进行销毁前的一些操作,比如说资源释放等。这个虚引用对于对象而言完全是无感知的,有没有完全一样,但是对于虚引用的使用者而言,就像是待观察的对象的把脉线,可以通过它来观察对象是否已经被回收,从而进行相应的处理。

事实上,虚引用有一个很重要的用途就是用来做堆外内存的释放,DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。

虚引用是最弱的引用

虚引用对对象而言是无感知的,对象有虚引用跟没有是完全一样的

虚引用不会影响对象的生命周期

虚引用可以用来做为对象是否存活的监控

你可能感兴趣的:(java,java)