您好,登錄后才能下訂單哦!
這篇文章主要講解了“java中的引用有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“java中的引用有哪些”吧!
一、強(qiáng)引用
概念:當(dāng)對象不可達(dá)時,即可回收。
/** * 強(qiáng)引用。當(dāng)強(qiáng)引用指針不存在時,對象將被回收 * 也可以理解為 ROOT 引用消失時,對象將被回收 */ public class StrongReference { /** * jvm在執(zhí)行g(shù)c時 將回調(diào)該方法 * @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; // 手動調(diào)用gc System.gc(); } }
二、軟引用
概念: 當(dāng)內(nèi)存空間不足時,將被回收。
/** * Xmx2oM 設(shè)置最大堆內(nèi)存為20M * 軟引用 會在內(nèi)存空間不夠時,進(jìn)行 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("第一次執(zhí)行g(shù)c后 : byte[]:" + softReference.get()); byte[] bytes = new byte[1024*1024*12]; System.out.println("內(nèi)存不夠后 : byte[]:" + softReference.get()); } }
上述代碼的補(bǔ)充:源碼中,我將虛擬機(jī)參數(shù) -Xmx 設(shè)置為20M。 我先后 new 出來的 兩個byte 數(shù)組均超過10M。 目標(biāo)對象均會存放在老年代中。(按照 新生代 : 老年代 = 1:2.) 大概內(nèi)存分布為。 老年代 20 * 2/3 約為13.3M。 年輕代 約為 20 * 1/3 約為 6.7M。其中 年輕代 eden:s0:s1 = 8:1:1 故 Eden 約為 5.3 M 。So/S1 約為0.67M。 如下圖所示,基本跟計(jì)算出來的結(jié)果吻合。至于 多出來的部分,個人理解,jvm對計(jì)算出的堆大小自我調(diào)優(yōu)勒。
基于對堆內(nèi)存的分析??梢钥闯?。 第一次 老年代 裝入 10 M的 對象。 第二次 想要 裝入 12M 對象??隙ㄑb不下。 由于是 軟引用。 jvm gc 時會將這部分內(nèi)容先回收掉。 所以這里沒有 出現(xiàn)OOM 的問題。
三、弱引用 (比較重要,面試??碱}之一)
備注: ThreadLocal 里使用勒 弱引用。會產(chǎn)生內(nèi)存泄露的問題。詳見 ( https://my.oschina.net/u/4141142/blog/4523523 )
概念:jvm無視該引用。該對象可被弱引用對象獲取到對象的實(shí)例。 當(dāng)jvm執(zhí)行g(shù)c時,將直接被回收。(提前條件:沒有強(qiáng)引用存在)。
示例一:
/** * 弱引用 虛擬機(jī)無視該引用。只要gc 一定會被回收(前提該對象沒有被強(qiáng)引用) */ 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,則還存在一個強(qiáng)引用。不會被gc回收 //teacher = null; System.gc(); System.out.println(weakReference.get()); }
示例二:
/** * User 對象持有 Teacher 對象的強(qiáng)引用。 * 當(dāng)teacher 被置為null 時。 teacher 的強(qiáng)應(yīng)用 隨之消失。 * 而 User 對 Teacher 的強(qiáng)引用還在。 故 user.getTeacher() 并不是null * 所以 teacher 并不會被 gc 回收。 * * 當(dāng) user 也被置為null時。 user 對 teacher 的強(qiáng)引用也不存在勒。 * 此時 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()); // 當(dāng)user 置為null 時, 對teacher 的強(qiáng)引用消失。 此時 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時,強(qiáng)引用指針被清除。 * 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()); } }
四、虛引用
概念:該引用很雞肋。一個對象被虛引用所引用時。并不能獲取到該實(shí)例的對象。只有當(dāng)該對象被回收時,才會收到通過并存入隊(duì)列中。基本上用于操作直接內(nèi)存來使用的。 可用于對一些重要對象的gc的監(jiān)聽?;蛘弑O(jiān)聽gc的頻率(不如打印gc日志來的簡單直觀)。
以下 jvm參數(shù) -Xmx20M。 當(dāng)然也可以更小,主要是為了看gc 的效果。
/** * 虛擬引用 * 比較雞肋,虛擬引用的對象,并不能get()出來。 而是直接操作 操作系統(tǒng)內(nèi)存的。 * 虛擬引用的目標(biāo)對象,被回收后,會存入隊(duì)列中 * 需要新啟一個線程監(jiān)聽該隊(duì)列中,是否有數(shù)據(jù)。有數(shù)據(jù) 則 回收掉直接內(nèi)存。 */ 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中的引用有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對java中的引用有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。