虛引用在垃圾回收時候,搶救不了了。對象回收的時候直接回收,如果用ReferenceQueue,那么在回收時候通過這個隊列,可以人為做些處理。軟引用弱引用先置位referent為null回收堆內存,然后把虛引用對象加入隊列,最后在隊列里面回收虛引用對象。
虛引用必須要和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)聯合使用。
當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之 關聯的引用隊列中。
虛引用里面的對象沒有強引用時候,開始回收,加入到隊列去,並不會置referent為null。
軟引用弱引用里面的對象沒有強引用時候,開始回收,加入到隊列去,置referent為null。
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在創建的時候分配內存。/
