16

Czy SoftReference i WeakReference naprawdę pomaga tylko wtedy, gdy zostały utworzone jako zmienne instancji? Czy są jakieś korzyści z ich zastosowania w zakresie metody?Korzystanie z Java's ReferenceQueue

Inna duża część to ReferenceQueue. Oprócz możliwości śledzenia, które referencje są określane jako śmieci, czy można użyć Reference.enqueue() do wymuszonego rejestrowania obiektu do zbierania śmieci?

Na przykład, czy byłoby warto stworzyć metodę, która zabiera trochę ciężkich zasobów pamięci (przechowywanych przez silne referencje) w obiekcie i tworzenie odnośników do ich kolejkowania?

Object bigObject; 
public void dispose() { 
    ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 
    WeakReference<Object> ref = new WeakReference<Object>(bigObject, queue); 
    bigObject = null; 
    ref.enqueue(); 
} 

(Wyobraźmy sobie, że w tym przypadku obiekt reprezentuje typ obiektu, który używa dużo pamięci ... jak BufferedImage lub coś)

to ma żadnego realistyczny efekt? A może to tylko strata kodu?

+0

Łagodnie powiązane: https://codereview.stackexchange.com/q/28534/4394 – Pacerier

Odpowiedz

26

Jedną wspólną idiom z kolejek odniesienia jest np podklasa WeakReference, aby załączyć informacje potrzebne do porządkowania rzeczy, a następnie odpytać ReferenceQueue, aby uzyskać zadania porządkowania.

ReferenceQueue<Foo> fooQueue = new ReferenceQueue<Foo>(); 

class ReferenceWithCleanup extends WeakReference<Foo> { 
    Bar bar; 
    ReferenceWithCleanup(Foo foo, Bar bar) { 
    super(foo, fooQueue); 
    this.bar = bar; 
    } 
    public void cleanUp() { 
    bar.cleanUp(); 
    } 
} 

public Thread cleanupThread = new Thread() { 
    public void run() { 
    while(true) { 
     ReferenceWithCleanup ref = (ReferenceWithCleanup)fooQueue.remove(); 
     ref.cleanUp(); 
    } 
    } 
} 

public void doStuff() { 
    cleanupThread.start(); 
    Foo foo = new Foo(); 
    Bar bar = new Bar(); 
    ReferenceWithCleanup ref = new ReferenceWithCleanup(foo, bar); 
    ... // From now on, once you release all non-weak references to foo, 
     // then at some indeterminate point in the future, bar.cleanUp() will 
     // be run. You can force it by calling ref.enqueue(). 
} 

Na przykład, wewnętrzne z CacheBuilder realizacji guawy, gdy weakKeys wybiera uses to podejście.

+0

Więc czy czeka aż kolejka zostanie zakolejkowana, a następnie wywoła cleanUp? Czy oni kiedykolwiek faktycznie wywołują enqueue()? – bgroenks

+0

Zgodnie z ['enqueue doc] (http://docs.oracle.com/javase/6/docs/api/java/lang/ref/Reference.html#enqueue()), w rzeczywistości nie potrzebujesz aby wywołać 'włącz". Obiekt referencyjny zostanie dodany do kolejki referencyjnej, gdy odesłany obiekt otrzyma GC. –

+1

Mówi także, że GC go nie używa. Dlaczego więc istnieje, zastanawiam się? – bgroenks

5

Jeśli obiekt ma tylko WeakReference s (lub nie ma żadnych odniesień!) W jego kierunku, może on zostać zebrany, gdy Java potrzebuje więcej miejsca w pamięci. Tak więc używasz WeakReference s, gdy chcesz, aby obiekt pozostał w pamięci, ale nie musisz go tak źle (np. Jeśli Java musi go usunąć, nie ma problemu, możesz go jakoś odzyskać i czas Java ma lepszą wydajność)

Enqueuing a WeakReference pozwala na iterację ReferenceQueue i określenie, które referencje zostały zebrane śmieci, a które nie. To wszystko - więc rób to tylko, jeśli musisz to wiedzieć.

Więcej: http://weblogs.java.net/blog/2006/05/04/understanding-weak-references

+0

Wiem o tym. Ale moje pytanie brzmi, czy metoda enqueue() wymusza na WeakReference zbieranie śmieci lub rejestrowanie ich do zbierania śmieci? – bgroenks

+0

Nie. Jeśli potrzebujesz go teraz do zbierania śmieci, usuń wszystkie silne referencje i powiedz, że śmieciarz działa. – Patashu

+0

Nie sądzę, że jest to gwarantowane. Co właściwie robi program enqueue()? – bgroenks

3

Jedną z powszechnych rzeczy jest tworzenie map miękkich odniesień.

Map<String, SoftReference<BigThing>> cache = new HashMap<>(); 
Set<String> thingsIAmCurrentlyGetting = new HashSet<String>(); 
Object mutex = new Object(); 

BigThing getThing(String key) { 
    synchronized(mutex) { 
    while(thingsIAmCurrentlyGetting.contains(key)) { 
     mutex.wait(); 
    } 
    SoftReference<BigThing> ref = cache.get(key); 
    BigThing bigThing = ref == null ? null : ref.get(); 
    if(bigThing != null) return bigThing; 
    thingsIAmCurrentlyGetting.add(key); 
    } 

    BigThing bigThing = getBigThing(key); // this may take a while to run. 

    synchronized(mutex) { 
    cache.put(key, bigThing); 
    thingsIAmCurrentlyGetting.remove(key); 
    mutex.notifyAll(); 
    } 

    return bigThing; 
} 

Pokazuję tutaj moją starą szkołę - nowe pakiety java prawdopodobnie mają o wiele więcej sposobów na zrobienie tego.

+0

Och, trzymaj się - to wcale nie było twoje pytanie! To zupełnie nieistotne! – PaulMurrayCbr

+0

Szczerze mówiąc, jest to naprawdę bardzo dobry przykład, jak prawidłowo używać miękkiego/słabego odniesienia do poprawnie leniwych inicjalizacji obiektów (bez warunków wyścigu lub Zablokuj), który powiadamia o innych oczekujących wątkach ... Zapomniał o tym powiedzieć nie, tworzenie i zapisywanie odnośników nie pomoże w ogóle i jest marnowaniem kodu. Potrzebujesz wszystkich TWOICH non-gc'd odniesień do dużego obiektu, aby je anulować (aby zapobiec GC ...) – Ajax

0

Nie wiem, co jest tutaj, ale pytanie:

1) miękkie ref starają się zachować odniesienie aż JVM naprawdę bardzo potrzebuje pamięci. Idealne dla pamięci podręcznych, szczególnie tych LRU. Spójrz na wiele przykładów w Guava.

2) słaby ref nie próbuj w żaden sposób uniemożliwić gc uwolnienia obiektu. Są używane, jeśli chcesz się dowiedzieć, czy ten obiekt jest gdzieś używany. Na przykład są one używane do przechowywania informacji o wątkach i klasach, więc gdy wątek lub klasa nie jest już używana, możemy odrzucić metainfo związane z tym.

3) Phantom Ref są słabe, ale bez możliwości odniesienia się do rzeczywistego obiektu. W ten sposób możesz być pewny, że przekazanie fantomu dookoła nie może wznowić obiektu (jest to ryzyko ze słabym ref).Również phantom ref blokuje obiekt, który ma zostać zebrany, dopóki nie usuniesz ref.

ReferenceQueue: nie zawiera tam żadnych rzeczy. gc zrobi dla ciebie. Pozwalają ci dowiedzieć się, kiedy niektóre referencje zostaną opublikowane, bez konieczności sprawdzania ich pojedynczo.