2011-07-14 11 views
8

Rozumiem, że gdy przydzielono nam bezpośredni kontakt, nie można go pozbyć się, ale zastanawiam się, czy obiekt do pakowania jest zbędny.Czy pakunki Java DirectByteBuffer są zbierane?

Na przykład, jeśli przydzieliłem nową dbb DirectByteBuffer, a następnie powielono (płytko skopiowałem) przy użyciu dbb.duplicate(), miałem dwa opakowania wokół tego samego kawałka pamięci.

Czy te opakowania są przedmiotem zbiórki śmieci? Gdybym miał

while(true){ 
    DirectByteBuffer dbb2 = dbb.duplicate(); 
} 

Czy w przyszłości sam OOM?

+0

Właściwie DirectByteBuffer i jego pamięć natywna _might_ mogą być zbierane. Używa PhantomReference do zwolnienia natywnej pamięci przydzielonej. –

Odpowiedz

10

W Sun JDK, o java.nio.DirectByteBuffer — stworzony przez ByteBuffer#allocateDirect(int) — ma pole typu sun.misc.Cleaner, która rozciąga java.lang.ref.PhantomReference.

Gdy ta Cleaner (należy pamiętać, podtypu PhantomReference) zostaje zebrane i wprowadzają się w odpowiednią ReferenceQueue gwint związane kolekcji uruchomiony przez pod-typ ReferenceHandler ma szczególnego traktowania przypadek Cleaner przypadkach: to downcasts i wywołuje Cleaner#clean(), która ostatecznie powraca do wywoływania DirectByteBuffer$Deallocator#run(), która z kolei wywołuje Unsafe#freeMemory(long). Łał.

Jest to dość okrężne i byłem zaskoczony, że nie widzę żadnego użytku w grze w postaci Object#finalize(). Deweloperzy Sun mieli swoje powody, aby powiązać to jeszcze bardziej z podsystemem zarządzania kolekcjami i referencjami.

Krótko mówiąc, nie zabraknie pamięci poprzez rezygnację z odwołań do instancji DirectByteBuffer, o ile odśmiecacz ma szansę zauważyć przerwanie, a jego wątek obsługi referencyjnej powoduje postęp w wywołaniach opisanych powyżej.

+2

Zauważ, że jeśli używasz '-XX: + DisableExplicitGC', możesz napotkać więcej błędów' OutOfMemory' z 'allocateDirect'. Alokacja próbuje zarezerwować pamięć i wywołuje 'System.gc()', jeśli nie może, aby wyzwolić odzyskiwanie 'PhantomReference'. –

1

Po odszukaniu kodu źródłowego do DirectByteBuffer po prostu zwraca nową instancję, więc nie, sam OOM nie będzie.

Tak długo, jak reszta kodu nie będzie zawierała odniesienia do oryginału dbb, wówczas obiekt będzie zbierał śmieci w normalny sposób. Dodatkowe obiekty dbb2 będą podobnie zbierać śmieci, gdy nie będzie już żadnych odniesień do nich (np. Koniec pętli while).

2

Bezpośredni obiekt ByteBuffer jest jak każdy inny obiekt: może być zbierany śmieci.

Pamięć używana przez bufor bezpośredni zostanie zwolniona, gdy obiekt ByteBuffer jest GC'd (nie jest to wyraźnie określone dla ByteBuffer, ale jest implikowane przez dokumentację MappedByteBuffer).

Tam, gdzie rzeczy stają się interesujące, to gdy wypełniłeś przestrzeń pamięci wirtualnych za pomocą bezpośrednich buforów, ale nadal masz dużo miejsca w stercie. Okazuje się, że (przynajmniej na Sun JVM), wyczerpanie przestrzeni wirtualnej przy przydzielaniu bufora bezpośredniego wyzwala GC sterty Java. Które mogą zbierać nieokreślone bufory bezpośrednie i zwolnić ich zaangażowanie w pamięć wirtualną.

Jeśli używasz maszyny 64-bitowej, powinieneś użyć -XX:MaxDirectMemorySize, która określa górny limit liczby buforów, które możesz przydzielić (a także uruchamia GC po osiągnięciu tego limitu).

+0

W jaki sposób korzystanie z funkcji DirectByteBuffers pomaga w wstrzymywaniu zbierania śmieci, ala TerraCotta's BigMemory? –

+0

@Li Pi: ponieważ można przechowywać wiele serializowanych obiektów Java w jednym bezpośrednim buforze. – parsifal

-2

gdy directbytebuffer jest przydzielona, ​​nie jest przedmiotem zbiórki śmieci

Skąd ten pomysł? To jest niepoprawne. Czy mieszasz je z MappedByteBuffers?

+0

@downvoter Dlaczego? – EJP

Powiązane problemy