您好,登錄后才能下訂單哦!
這篇文章主要講解了“java中的引用有哪些”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“java中的引用有哪些”吧!
一、強引用
概念:當對象不可達時,即可回收。
/** * 強引用。當強引用指針不存在時,對象將被回收 * 也可以理解為 ROOT 引用消失時,對象將被回收 */ public class StrongReference { /** * jvm在執行gc時 將回調該方法 * @throws Throwable */ @Override protected void finalize() throws Throwable { System.out.println("gc doing now !"); } public static void main(String[] args) { StrongReference strongReference = new StrongReference(); // 將引用指針移除 strongReference = null; // 手動調用gc System.gc(); } }
二、軟引用
概念: 當內存空間不足時,將被回收。
/** * Xmx2oM 設置最大堆內存為20M * 軟引用 會在內存空間不夠時,進行 gc 操作。 從而 回收 軟引用對象 */ public class MySoftReference { public static void main(String[] args) { SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]); System.out.println("第一次gc前 : byte[]:" + softReference.get()); System.gc(); System.out.println("第一次執行gc后 : byte[]:" + softReference.get()); byte[] bytes = new byte[1024*1024*12]; System.out.println("內存不夠后 : byte[]:" + softReference.get()); } }
上述代碼的補充:源碼中,我將虛擬機參數 -Xmx 設置為20M。 我先后 new 出來的 兩個byte 數組均超過10M。 目標對象均會存放在老年代中。(按照 新生代 : 老年代 = 1:2.) 大概內存分布為。 老年代 20 * 2/3 約為13.3M。 年輕代 約為 20 * 1/3 約為 6.7M。其中 年輕代 eden:s0:s1 = 8:1:1 故 Eden 約為 5.3 M 。So/S1 約為0.67M。 如下圖所示,基本跟計算出來的結果吻合。至于 多出來的部分,個人理解,jvm對計算出的堆大小自我調優勒。
基于對堆內存的分析。可以看出。 第一次 老年代 裝入 10 M的 對象。 第二次 想要 裝入 12M 對象。肯定裝不下。 由于是 軟引用。 jvm gc 時會將這部分內容先回收掉。 所以這里沒有 出現OOM 的問題。
三、弱引用 (比較重要,面試常考題之一)
備注: ThreadLocal 里使用勒 弱引用。會產生內存泄露的問題。詳見 ( https://my.oschina.net/u/4141142/blog/4523523 )
概念:jvm無視該引用。該對象可被弱引用對象獲取到對象的實例。 當jvm執行gc時,將直接被回收。(提前條件:沒有強引用存在)。
示例一:
/** * 弱引用 虛擬機無視該引用。只要gc 一定會被回收(前提該對象沒有被強引用) */ public class Test { public static void main(String[] args) { Teacher teacher = new Teacher(); WeakReference<Teacher> weakReference = new WeakReference<Teacher>(teacher); System.out.println(weakReference.get()); // 若不將 teacher 置為null,則還存在一個強引用。不會被gc回收 //teacher = null; System.gc(); System.out.println(weakReference.get()); }
示例二:
/** * User 對象持有 Teacher 對象的強引用。 * 當teacher 被置為null 時。 teacher 的強應用 隨之消失。 * 而 User 對 Teacher 的強引用還在。 故 user.getTeacher() 并不是null * 所以 teacher 并不會被 gc 回收。 * * 當 user 也被置為null時。 user 對 teacher 的強引用也不存在勒。 * 此時 teacher 將會被gc回收 */public class Test1 {public static void main(String[] args) { User user = new User(); Teacher teacher = new Teacher(); teacher.setName("zs"); user.setTeacher(teacher); WeakReference<Teacher> weakReference = new WeakReference<Teacher>(teacher); System.out.println(System.identityHashCode(weakReference.get())); System.out.println(System.identityHashCode(teacher)); System.out.println(System.identityHashCode(user.getTeacher())); teacher = null; System.out.println(user.getTeacher().getName()); // 當user 置為null 時, 對teacher 的強引用消失。 此時 teacher 將會被回收。 user = null; System.gc(); System.out.println(weakReference.get()); } }
示例三:
public class People extends WeakReference<Teacher> { public People(Teacher referent) { super(referent); } } /** * People 繼承自WeakReference<T> People也是一個虛擬引用對象。 * 所以teacher 被置為null時,強引用指針被清除。 * teacher 就會被gc回收。 */ public class Test2 { public static void main(String[] args) { Teacher teacher = new Teacher(); People people = new People(teacher); teacher = null; System.gc(); System.out.println(people.get()); } }
四、虛引用
概念:該引用很雞肋。一個對象被虛引用所引用時。并不能獲取到該實例的對象。只有當該對象被回收時,才會收到通過并存入隊列中。基本上用于操作直接內存來使用的。 可用于對一些重要對象的gc的監聽。或者監聽gc的頻率(不如打印gc日志來的簡單直觀)。
以下 jvm參數 -Xmx20M。 當然也可以更小,主要是為了看gc 的效果。
/** * 虛擬引用 * 比較雞肋,虛擬引用的對象,并不能get()出來。 而是直接操作 操作系統內存的。 * 虛擬引用的目標對象,被回收后,會存入隊列中 * 需要新啟一個線程監聽該隊列中,是否有數據。有數據 則 回收掉直接內存。 */ public class MyPhantomReference { private static final List<Object> LIST = new LinkedList<Object>(); private static final ReferenceQueue<MyPhantomReference> QUEUE = new ReferenceQueue<MyPhantomReference>(); public static void main(String[] args) { PhantomReference<MyPhantomReference> phantomReference = new PhantomReference<MyPhantomReference>(new MyPhantomReference(),QUEUE); new Thread( () -> { while(true){ LIST.add(new byte[1024*1024]); try{ Thread.sleep(1000); }catch(Exception e){ e.printStackTrace(); Thread.currentThread().interrupt(); } System.out.println(phantomReference.get()); } }).start(); new Thread( () -> { while(true){ Reference<? extends MyPhantomReference> poll = QUEUE.poll(); if(poll != null){ System.out.println("虛擬引用被jvm回收啦 ----" + poll); } } }).start(); try{ Thread.sleep(500); }catch(Exception e){ e.printStackTrace(); } } }
感謝各位的閱讀,以上就是“java中的引用有哪些”的內容了,經過本文的學習后,相信大家對java中的引用有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。