虚引用

虚引用在垃圾回收时候,抢救不了了。对象回收的时候直接回收,如果用ReferenceQueue,那么在回收时候通过这个队列,可以人为做些处理。软引用弱引用先置位referentnull回收堆内存,然后把虚引用对象加入队列,最后在队列里面回收虚引用对象。

 

虚引用必须要和ReferenceQueue结合使用软引用弱引用可以不和ReferenceQueue结合使用。

 

强引用 : 就是普通的引用. 内存不足抛 Out of Memory 异常

软引用(SoftReferenve) : 内存充足的情况下不会被回收,内存不充足的情况下才会被回收。能够很好地规避OOM异常。

弱引用(WeakReference) : 当垃圾回收机制运行时, 弱引用引用的对象就会被回收掉.

 

// 新建一个引用队列

ReferenceQueue<TestObject> referenceQueue = new ReferenceQueue<>();

// 建立一个TestObject的弱引用

SoftReference<TestObject> reference = new SoftReference<>(new TestObject(), referenceQueue)

引用和软引用在创建的时候都可以传进去一个引用队列(当然也可以不使用引用队列), 当弱引用和软引用引用的对象需要进行回收的时候, JVM都是先将其referent字段设置成null,之后将软引用或弱引用对象本身,加入到关联的引用队列中。也就是说JVM先回收堆对象内存,然后才将软引用或弱引用本身加入到引用队列。

 

// 创建一个引用队列

ReferenceQueue<TestObject> referenceQueue = new ReferenceQueue<>();

PhantomReference reference = new PhantomReference<>(new TestObject(), referenceQueue);

而虚引用(PhantomReference) 不同, 必须和引用队列 ReferenceQueue)联合使用, GC启动时, 则将引用对象传到它的引用队列中去. 但是不会将虚引用的referent字段设置成null, 就是不会释放虚引用指向的TestObject堆对象内存空间

 

如果虚引用引用的对象重写了finalize方法, 在虚引用对象传到它的引用队列之前还会调用对象的finalize方法, 但是调用之后内存不会回收.
你可以通过手动调用PhantomReference.clear()方法来释放虚引用指向的的堆对象内存空间

 

虚引用的存在更倾向于实现程序员对内存回收的细粒度性控制, 当虚引用确定会被回收之后, 会向应用程序发送通知, 此时程序员进行对内存清理的细微操作.

 

public static void main(String[] args) {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);
        System.out.println(weakRef.get());//返回weakRef里面的obj
        System.out.println(refQueue.poll());//队列灭有元素
        obj = null;//只有weakRef 指向new Object()内存,不置位null,gc时候不会将weakRef 的eferent被置位了null,也不会将weakRef加入refQueue队列
        System.gc();
        System.gc();
        System.gc();
        System.gc();//System.gc()是告诉JVM这是一个执行GC的好时机,但具体执不执行由JVM决定,
        System.out.println(weakRef.get());//referent被置位了null
        System.out.println(refQueue.poll());//队列里面有一个元素weakRef但是weakRef的referent被置位了null
    }

 

 public class Test0009 {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);
        System.out.println(phanRef.get());//null,phanRef里面有元素但是一直返回null,因为PhantomReference重写了Reference的get方法,写死了返回null
        System.out.println(refQueue.poll());//队列为空,
        obj = null;//不置位null,phanRef里面有元素,队列为空。
        System.gc();
        System.gc();
        System.gc();
        System.out.println(phanRef.get());//phanRef里面仍然有元素,referent并没有像弱引用软引用那样置位空
        System.out.println(refQueue.poll());//队列有元素,
    }
}
class Registry {
    private Set registeredObjects = new HashSet();
 
    public void register(Object object) {
        registeredObjects.add( object );
    }
}
所有我添加进 registeredObjects 中的object永远不会被GC回收,因为这里有个强引用保存在registeredObjects里,
object 内存对象被2个强引用关联。另一方面如果我把代码改为如下:
class Registry {
     private Set registeredObjects = new HashSet();
 
     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }
现在如果GC想要回收registeredObjects中的object,object 内存对象被1个强引用1个弱引用关联,便能够实现了,
同样在使用HashMap如果想实现如上的效果,一种更好的实现是使用WeakHashMap

强引用:一直不回收

软引用:内存不足回收

弱引用:gc就回收

虚引用:  “虚引用”顾名思义,就是形同虚设,一个对象仅持有虚引用,那么它就和没有任何引用一样。虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用必须和引用队列 ReferenceQueue)联合使用。

当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

虚引用里面的对象没有强引用时候,开始回收,加入到队列去,并不会置referentnull

软引用弱引用里面的对象没有强引用时候,开始回收,加入到队列去,置referentnull

 

public class MyDate extends Date { 

    /** Creates a new instance of MyDate */
    public MyDate() {
    }
    // 覆盖finalize()方法,finalize()函数是在JVM回收内存时执行的,
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("obj [Date: " + this.getTime() + "] is gc");
    }   

    public String toString() {
        return "Date: " + this.getTime();
    }
}

 

虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个仅仅持有虚引用的对象,和没有引用几乎是一样的,随时都有可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。

当你的虚引用所引用的对象已经执行完finalize函数的时候,就会把对象加到queue里面。

广义的堆外内

-Xmx的值是新生代和老生代的和的最大值,-XX:MaxPermSize来指定持久代的最大值Java堆的最大值其实是-Xmx和-XX:MaxPermSize的总和

那么剩下的都可以认为是堆外内存(广义的)了,这些包括了jvm本身在运行过程中分配的内存,codecache,jni里分配的内存,DirectByteBuffer分配的内存等等

狭义的堆外内存

这个主要是指java.nio.DirectByteBuffer在创建的时候分配内存/

 

 

posted @ 2019-06-04 18:05  无天666  阅读(1363)  评论(0编辑  收藏  举报