簡體   English   中英

Java - WeakReference最佳實踐

[英]Java - WeakReference best practices

我將在這個問題上加上我不熟悉Java垃圾收集的聲明,所以如果收集器處理問題,我會對此感到高興。 或者,如果我無聊的Java內存分配,我實際上是,我道歉。 但是,我正在考慮以下三種情況:

public class ScenarioA implements MyQuestion{

    private Field field;

    public Field getField(){
        if(field == null){
           field = new Field(this);
        }
        return field;
}

  public class ScenarioB implements MyQuestion{

    public Field getField(){
        return new Field(this);
    }
}

import java.lang.ref.WeakReference;

public class ScenearioC implements MyQuestion{

    private WeakReference<Field> weakField;

    public Field getField(){
        if(WeakField == null || weakField.get() == null){
            weakField = new WeakReference(new Field(this));
        }
        return weakField.get();
    }
}

我認為ScenarioA很糟糕,因為如果在ScenarioA的實例上調用了.get() ,我們將在ScenarioA的實例和.get()方法返回的Field實例之間保持強引用,這意味着無論程序是否真正關心任何一個,都將被垃圾收集。

ScenarioB存在潛在地實例化大量.equal對象的問題,這可能非常昂貴且不必要。

ScebarioC我最不懂。 我試圖閱讀WeakReference的源代碼( 這里 ),但我無法弄清楚發生了什么。 我想責怪在幕后發生的某些GC / VM操作,但我想在很多其他事情上責怪很多事情。 無論如何,在我看來,每個WeakReference必須要求嚴格的內存而不是簡單地維護對引用的引用,因為我們必須首先維護對WeakReference ,然后WeakReference維護對實際對象的引用。 (我為那句話道歉)。 如果Field很大並且/或者我們實例化了幾個ScenarioA那么這可能會很糟糕。 更重要的是,在我看來,每個WeakReference需要自己的線程,除非實例ScenarioC - 因此弱引用 - 死亡,否則它本身(線程)似乎永遠不會消亡。 如果有很多ScenarioC實例,這可能會非常糟糕。

有沒有人有這個問題的解決方案?

在考慮使用WeakReference ,您應該問問自己,如果沒有強烈的目標引用,它們會立即失效。 WeakReference適當的大多數地方,這種行為是可取的; 如果在特定情況下這種行為是不受歡迎的,那通常表明某種其他形式的緩存更合適。

從根本上說, WeakReference通常不適合建立與目標對象本身的連接,而是建立與引用目標對象的其他事物的間接連接。 當沒有其他東西引用目標對象時,弱引用將變得無用,應該被消除。

例如,考慮一個對象Joe其目的是讓任何有興趣的人知道Fred對象做了多少次。 它要求Fred在它執行相關操作時讓它知道(通過調用方法),並且每次調用該方法時Joe都會增加一個計數器。 在這種情況下,Fred要么對Joe持有弱引用,要么保留對Joe的弱引用的引用。 畢竟,弗雷德並不關心這個櫃台 - 它唯一的興趣是確保每個想知道其行為的人都會發現它們。 Fred對Joe本身並不感興趣,而是因為其他實體可能對Joe感興趣。 一旦沒有其他人對喬感興趣,弗雷德應該沒有理由。

關於您的示例,如果使用與先前請求相同的對象填充將來請求的好處主要源於對該對象的其他引用的存在,則弱引用將是適當的。 如果不了解有關對象的使用模式,就無法確定它們是否符合該描述。 然而,這是我在決定是否使用弱引用時要關注的問題。

我建議使用WeakReference最佳實踐的唯一建議是不要使用它們除非你真的必須這樣做 他們無法幫助您嘗試做什么。

您似乎擔心制作太多對象 - 這是Java新手的常見錯誤。 制作對象並釋放它們是Java中的一個基本機制,並且已被調整為異常高效。 您需要擔心的唯一考慮因素是對象是否需要花費大量時間來構建或占用大量空間。 在這種情況下,您應該考慮使用池(可能在幕后使用WeakReference )。

另一個需要考慮的選擇是使用Singleton

您無法通過查看其源代碼來推導WeakReference工作方式。 垃圾收集器知道WeakReference類的特殊語義並相應地處理它的referent 當你真的需要使用WeakReference你必須意識到它的get方法總是可以返回null ,只要沒有對它的referent普通(也就是強)引用,即使你只是在它之前檢查了get的返回值,即使您剛剛在它之前創建了WeakReference

您必須使用強引用(例如在局部變量中)來保存新實例或在返回之前檢查WeakReference.get()返回的實例:

import java.lang.ref.WeakReference;

public class ScenarioC implements MyQuestion {

    private WeakReference<Field> weakField;

    public Field getField() {
      if(weakField!=null) {
        Field field = weakField.get(); // create an ordinary strong reference
        if(field!=null) return field; // the strong reference works as known
      }
      Field field=new Field(this); // keep the new instance ordinarily
      weakField = new WeakReference<Field>(field);
      return field; // return the ordinary strong reference to the new instance
    }
}

請注意,此代碼仍然不是線程安全的,它僅顯示在使用WeakReference時如何處理可能的垃圾回收。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM