垃圾收集算法,垃圾收集器_弱,弱,最弱,利用专家参考来管理垃圾收集器
垃圾收集算法,垃圾收集器
何時以及何時不使用Java中的專家引用
弱引用,軟引用和幻像引用既危險又強大。 如果以錯誤的方式使用它們,則會破壞JVM性能。 但是,如果使用正確的方法,它們可以大大提高性能和程序清晰度。
弱引用和軟引用在這三種中更為明顯。 實際上,它們幾乎是同一件事! 這個想法很簡單,就是將它們用于訪問對象,但不會阻止垃圾回收器回收該對象:
您發現故意的錯誤嗎? 這是一個容易錯過的東西,并且可能不會在單元測試中顯示。 這正是讓我說的問題:
僅在絕對必要且可能甚至沒有的情況下,才使用弱/軟引用。
當JVM承受內存壓力時,它可能會在弱引用中的get方法的第一次和第二次調用之間回收該對象。 當在null上調用toString方法時,這將導致程序引發null指針異常。 該代碼的正確形式為:
Object x=x.get(); // Now we have null xor a hard reference to // the object if(z==null){System.out.println("The object has gone away"); }else{System.out.println("The object is " + z.toString()); }我們為什么要他們?
我們還沒有完全談到為什么它們真的非常危險。 為此,我們需要了解為什么我們可能需要它們以及為什么我們需要它們。 在兩種常見的情況下,弱引用和軟引用似乎是個好主意(我們將在稍后介紹軟和弱引用之間的區別)。 首先是某種形式的RAM緩存。
它是這樣的:
我們有一些數據,例如客戶詳細信息,存儲在數據庫中。 我們一直在尋找它,這很慢。 我們可以做的是將這些數據緩存在RAM中。 但是,最終RAM將填充名稱和地址,并且JVM拋出OutOfMemoryError。 解決方案是將名稱和地址存儲在只能弱訪問的對象中。 像這樣:
ConcurrentHasMap>String,WeakReference>CustomerInfo<< cache=new ConcurrentHashMap><(); ... CustomerInfo currentCustomer=cache.get(customerName); if(currentCustomer==null){currentCustomer=reloadCachesEntry(customerName); }這種無害的小模式非常有能力使巨型的JVM崩潰。 該模式使用JVM的垃圾回收器來管理內存中的緩存。 垃圾收集器從未被設計為這樣做。 該模式通過用難以到達的對象填充內存來濫用垃圾收集器,這些對象使JVM耗盡了堆空間。 當JVM的內存不足時,它必須遍歷其堆中的所有引用(弱引用,軟引用和其他引用)并回收RAM。 這是昂貴的并且顯示為處理成本。 在具有許多處理器核心的超大型JVM實例上,情況甚至更糟,因為垃圾收集器很可能最終不得不執行“停止世界”的完整循環,從而將性能降低到單核級別!
我并不是說內存緩存技術不是一個好主意。 哦,不,這是個好主意。 但是,僅將其扔到垃圾收集器上并且不期望麻煩是一種非常糟糕的設計選擇。
弱vs軟
有什么區別? 好吧,真的有很多。 在某些JVM(例如,客戶端托管JVM的客戶端,但可能隨時更改)上,弱引用被標記為優先垃圾收集。 換句話說,與其他內存相比,垃圾回收器應更努力地從它們引用的對象圖中回收內存(并且不引用軟或硬引用)。 軟引用對他們沒有這個想法。 但是,這只是某些JVM上的可選概念,不能被依賴,而且還是一個壞主意。 我建議始終使用軟引用或弱引用,并堅持使用它。 選擇您喜歡的聲音。 我更喜歡WeakReference這個名字,所以傾向于使用它。
還有一個區別。 被軟引用和弱引用而不是硬引用引用的對象可能會遇到這樣的情況,即仍然可以從弱引用的.get()方法中獲取,而不能從軟引用的.get()方法中獲取。 反之亦然,反之亦然。 依賴于此行為的代碼可能是錯誤的標題。
弱引用的良好用法
確實存在。 弱引用對跟蹤其他地方正在使用的對象很有用。 一個示例來自Sonic Field(音頻處理程序包)。 在此示例中,文件中的“插槽”包含音頻數據,并與內存中的對象相關聯。 該模型不使用弱引用來引用數據的內存中副本。 在內存對象中使用插槽。 弱引用用于允許文件管理系統重用插槽。
使用插槽的代碼不需要(也不應該)與磁盤空間的管理有關。 文件管理器很關心這樣做。 文件管理器對使用插槽的對象有較弱的引用。 當請求一個新的插槽時,文件管理器將檢查通過弱引用引用的所有現有插槽,這些弱引用已被回收(因此從get方法返回null)。 如果找到這樣的引用,則可以重用該插槽。
自動通知回收
有時,我們可能想知道何時回收了弱引用或軟引用(或其他類型的幻像)。 這可以通過排隊系統來完成。 我們可以使用參考隊列來做到這一點:
WeakReference(T referent, ReferenceQueue<? super T> q)我們做這樣的事情:
ReferenceQueue junkQ = new ReferenceQueue<>(); .... WeakReference<FileSlot> mySlot=new WeakReference<>(aSlot); .... // In a different thread - make sure it is daemon! WeakReference<FileSlot> isDead; while(true){isDead = junkQ.remove();// Take some action based on the fact it is dead// But - it might not be dead - see end of post :( ... }但是,請記住,當弱引用在junkQ上結束時,對其調用.get()將返回null。 如果您必須存儲信息以允許您感興趣的任何操作發生在其他地方(例如,ConcurrentHashMap,其中引用是關鍵),
那么什么是幻影引用?
虛擬引用是一種,當您需要它們時,您確實需要它們。 但是從表面上看,它們似乎毫無用處。 您會看到,每當在幻像引用上調用.get()時,總會返回null。 永遠不可能使用幻像引用來引用它所引用的對象。 好吧-這不是真的。 有時我們可以通過JNI來實現這一目標,但我們絕對不應該這樣做。
考慮一下您在與Java對象關聯的JNI中分配本機內存的情況。 這是JDK的noi包中的DirectBuffers使用的模型。 這是我在大型商業項目中反復使用的東西。
那么,我們如何回收本機內存呢?
對于類似文件的系統,可以說在關閉文件之前不會回收內存。 這將資源管理的責任放在程序員的肩膀上; 這正是程序員對文件之類的期望。 但是,對于重量較輕的對象,我們的程序員不喜歡考慮資源管理-垃圾收集器可以為我們做這件事。
我們可以將代碼放在終結器中,終結器調用JNI代碼來回收內存。 這是很糟糕的(就像致命的一樣),因為JVM幾乎可以保證它們將調用終結器。 所以,不要那樣做! 但是,幻象引用可以解救! 首先,我們需要理解“幻影可到達”:只有當幻象引用無法通過其他任何類型的引用(硬,弱或軟)到達時,它才會被排隊。 在這一點上,幻影參考可以入隊。 如果對象具有終結器,則它將被忽略或運行。 但它不會“將物體帶回生活”。 幻影可到達對象對于JNI本機代碼(或任何其他代碼)來說是“安全的”,可以根據資源回收資源。
因此,帶有幻像引用的代碼如下所示:
ReferenceQueue<FileSlot> junkQ = new ReferenceQueue<>(); .... Phantom<FileSlot> mySlot=new Phantom<>(aSlot); .... // In a different thread - make sure it is daemon! Phantom<FileSlot> isDead; while(true){isDead=junkQ.remove();long handle=lookUpHandle(isDead);cleanNativeMemory(handle); }在這種模式下,我們保留了一個句柄,本機代碼可使用該句柄在Java中的結構(可能是另一個哈希圖)中查找和回收資源。 當我們完全確定Java對象無法重生時-它是幻影可到達的(即幽靈-我們可以安全地回收本機資源。如果您的代碼使用sun.misc.unsafe進行了其他“頑皮的”事情(對于有關使用此技術的完整示例,請參見這篇文章 。
關于幻影引用的最后思考。 從技術上講,可以使用弱引用來實現與上述相同的模式。 但是,這并不是弱引用的目的,并且這種模式會濫用它們。 幻象引用絕對保證對象確實已死,因此可以回收資源。 僅舉一個例子,從理論上講,可以將弱引用加入隊列,然后由其終結器將對象恢復原狀,因為終結隊列的運行速度比弱參考隊列慢。 這種幻影恐怖故事不可能在幻影引用中發生。
有一個小問題,這是JVM設計的弱點。 也就是說,JNI全局弱引用類型與幻像引用具有未定義的關系。 有人建議即使將對象排隊為幻像引用,也可以使用全局弱引用來獲取對象。 這是對JVM的一種特定實現的怪癖,永遠不要使用。
參考: 弱,更弱,最弱,利用垃圾收集器 ,以及來自Java日歷日歷博客上我們JCG合作伙伴 Alexander Turner的專業參考 。
翻譯自: https://www.javacodegeeks.com/2012/12/weak-weaker-weakest-harnessing-the-garbage-collector-with-specialist-references.html
垃圾收集算法,垃圾收集器
總結
以上是生活随笔為你收集整理的垃圾收集算法,垃圾收集器_弱,弱,最弱,利用专家参考来管理垃圾收集器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse MicroProfile
- 下一篇: Java应用程序性能监视:复杂的分布式应