Satu-satunya hal yang saya tahu PhantomReference
adalah,
- Jika Anda menggunakan
get()
metodenya, itu akan selalu mengembalikannull
dan bukan objeknya. Apa gunanya itu? - Dengan menggunakan
PhantomReference
, Anda memastikan bahwa objek tidak dapat dibangkitkan darifinalize
metode.
Tapi apa gunanya konsep / kelas ini?
Pernahkah Anda menggunakan ini dalam salah satu proyek Anda atau apakah Anda memiliki contoh di mana kami harus menggunakan ini?
FakeReference
atauNonReference
.Jawaban:
Saya menggunakan
PhantomReference
s dalam jenis profiler memori yang sangat khusus dan sederhana untuk memantau pembuatan dan penghancuran objek. Saya membutuhkan mereka untuk melacak kehancuran. Tapi pendekatannya sudah ketinggalan zaman. (Ditulis pada tahun 2004 dengan target J2SE 1.4.) Alat pembuatan profil profesional jauh lebih kuat dan andal dan fitur Java 5 yang lebih baru seperti JMX atau agen dan JVMTI dapat digunakan untuk itu juga.PhantomReference
s (selalu digunakan bersama dengan antrian Referensi) lebih unggulfinalize
yang memiliki beberapa masalah dan oleh karena itu harus dihindari. Terutama membuat objek bisa dijangkau lagi. Ini bisa dihindari dengan idiom penjaga finalisator (-> baca lebih lanjut di 'Java Efektif'). Jadi mereka juga baru selesai .Selanjutnya
PhantomReference
sDan seperti yang ditulis psd pertama kali, Roedy Green memiliki ringkasan referensi yang bagus .
sumber
Sebuah umum potong dadu-up table penjelasan , dari Glosarium Jawa.
Yang tentu saja sesuai dengan dokumentasi PhantomReference :
Dan yang tak kalah pentingnya, semua detail berdarah ( ini adalah bacaan yang bagus ): Objek Referensi Java (atau Cara Saya Belajar untuk Berhenti Khawatir dan Mencintai OutOfMemoryError) .
Selamat membuat kode. (Tetapi untuk menjawab pertanyaan itu, saya hanya pernah menggunakan WeakReferences.)
sumber
Penjelasan bagus tentang penggunaan Referensi Phantom:
sumber
Saya menemukan kasus penggunaan yang praktis dan berguna
PhantomReference
yang adaorg.apache.commons.io.FileCleaningTracker
di proyek commons-io.FileCleaningTracker
akan menghapus file fisik saat objek penanda dikumpulkan sampah.Sesuatu yang perlu diperhatikan adalah
Tracker
kelas yang memperluasPhantomReference
kelas.sumber
INI HARUS DIBATALKAN DENGAN JAVA 9!
Gunakan
java.util.Cleaner
sebagai gantinya! (Atausun.misc.Cleaner
di JRE lama)Posting asli:
Saya menemukan bahwa penggunaan PhantomReferences memiliki jumlah jebakan yang hampir sama dengan metode finalizer (tetapi masalah yang lebih sedikit setelah Anda melakukannya dengan benar). Saya telah menulis solusi kecil (kerangka kerja yang sangat kecil untuk menggunakan PhantomReferences) untuk Java 8. Ini memungkinkan untuk menggunakan ekspresi lambda sebagai callback untuk dijalankan setelah objek telah dihapus. Anda dapat mendaftarkan callback untuk sumber daya dalam yang harus ditutup. Dengan ini saya telah menemukan solusi yang bekerja untuk saya karena membuatnya jauh lebih praktis.
https://github.com/claudemartin/java-cleanup
Berikut adalah contoh kecil untuk menunjukkan bagaimana panggilan balik didaftarkan:
class Foo implements Cleanup { //... public Foo() { //... this.registerCleanup((value) -> { try { // 'value' is 'this.resource' value.close(); } catch (Exception e) { logger.warning("closing resource failed", e); } }, this.resource); }
Dan kemudian ada metode yang lebih sederhana untuk tutup otomatis, melakukan hal yang sama seperti di atas:
this.registerAutoClose(this.resource);
Untuk menjawab pertanyaan Anda:
Anda tidak dapat membersihkan sesuatu yang tidak ada. Tapi bisa saja sumber daya itu masih ada dan perlu dibersihkan agar bisa dihilangkan.
Itu tidak harus melakukan apa pun dengan efek apa pun selain debugging / logging. Atau mungkin untuk statistik. Saya melihatnya lebih seperti layanan notifikasi dari GC. Anda juga dapat menggunakannya untuk menghapus data gabungan yang menjadi tidak relevan setelah objek dihapus (tetapi mungkin ada solusi yang lebih baik untuk itu). Contoh sering menyebutkan koneksi database untuk ditutup, tetapi saya tidak melihat bagaimana ini adalah ide yang bagus karena Anda tidak dapat bekerja dengan transaksi. Kerangka aplikasi akan memberikan solusi yang jauh lebih baik untuk itu.
Saya menggunakannya sebagian besar hanya untuk logging. Jadi saya bisa melacak elemen yang dihapus dan melihat bagaimana GC bekerja dan bisa diubah. Saya tidak akan menjalankan kode penting dengan cara ini. Jika ada sesuatu yang perlu ditutup maka itu harus dilakukan dalam pernyataan coba-dengan-sumber daya. Dan saya menggunakannya dalam pengujian unit, untuk memastikan saya tidak memiliki kebocoran memori. Cara yang sama seperti jontejj melakukannya. Tetapi solusi saya sedikit lebih umum.
sumber
Saya menggunakan PhantomReference dalam pengujian unit untuk memverifikasi bahwa kode yang diuji tidak menyimpan referensi unnessecary ke beberapa objek. ( Kode asli )
import static com.google.common.base.Preconditions.checkNotNull; import static org.fest.assertions.Assertions.assertThat; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import com.google.common.testing.GcFinalization; /** * Helps to test for memory leaks */ public final class MemoryTester { private MemoryTester() { } /** * A simple {@link PhantomReference} that can be used to assert that all references to it is * gone. */ public static final class FinalizationAwareObject extends PhantomReference<Object> { private final WeakReference<Object> weakReference; private FinalizationAwareObject(Object referent, ReferenceQueue<Object> referenceQueue) { super(checkNotNull(referent), referenceQueue); weakReference = new WeakReference<Object>(referent, referenceQueue); } /** * Runs a full {@link System#gc() GC} and asserts that the reference has been released * afterwards */ public void assertThatNoMoreReferencesToReferentIsKept() { String leakedObjectDescription = String.valueOf(weakReference.get()); GcFinalization.awaitFullGc(); assertThat(isEnqueued()).as("Object: " + leakedObjectDescription + " was leaked").isTrue(); } } /** * Creates a {@link FinalizationAwareObject} that will know if {@code referenceToKeepTrackOff} * has been garbage collected. Call * {@link FinalizationAwareObject#assertThatNoMoreReferencesToReferentIsKept()} when you expect * all references to {@code referenceToKeepTrackOff} be gone. */ public static FinalizationAwareObject createFinalizationAwareObject(Object referenceToKeepTrackOff) { return new FinalizationAwareObject(referenceToKeepTrackOff, new ReferenceQueue<Object>()); } }
Dan tesnya :
@Test public void testThatHoldingOnToAnObjectIsTreatedAsALeak() throws Exception { Object holdMeTight = new String("Hold-me-tight"); FinalizationAwareObject finalizationAwareObject = MemoryTester.createFinalizationAwareObject(holdMeTight); try { finalizationAwareObject.assertThatNoMoreReferencesToReferentIsKept(); fail("holdMeTight was held but memory leak tester did not discover it"); } catch(AssertionError expected) { assertThat(expected).hasMessage("[Object: Hold-me-tight was leaked] expected:<[tru]e> but was:<[fals]e>"); } }
sumber
Biasanya digunakan di
WeakReference
tempatPhantomReference
yang lebih tepat. Hal ini untuk menghindari masalah tertentu yaitu dapat menghidupkan kembali objek setelahWeakReference
dihapus / diantrekan oleh pengumpul sampah. Biasanya perbedaan itu tidak masalah karena orang tidak bermain-main dengan pengacau konyol.Menggunakan
PhantomReference
cenderung sedikit lebih mengganggu karena Anda tidak dapat berpura-pura bahwaget
metode tersebut berhasil. Anda tidak dapat, misalnya, menulisPhantom[Identity]HashMap
.sumber
weakref.get
bisa kembalinull
, dan kemudian masih bisa mengembalikan obj?finalize
tidak membuat ulang objek seperti itu. Itu bisa membuat objek sangat mudah dijangkau lagi setelahWeakReference
kembalinull
dariget
dan diantrekan. / (user166390: Seperti pada peta yang dikunci pada target referensi, sepertiWeakHashMap
halnya, bukan peta identitas referensi yang baik-baik saja.)Metode yang berguna untuk memanggil (daripada
get()
) akan menjadiisEnqueued()
ataureferenceQueue.remove()
. Anda akan memanggil metode ini untuk melakukan beberapa tindakan yang perlu dilakukan pada putaran terakhir pengumpulan sampah objek.Pertama kali sekitar adalah ketika objek memiliki
finalize()
metode yang dipanggil, jadi Anda bisa meletakkan kait penutup di sana juga. Namun, seperti yang dinyatakan orang lain, mungkin ada cara yang lebih pasti untuk melakukan pembersihan atau tindakan apa pun yang perlu dilakukan sebelum dan sesudah pengumpulan sampah atau, lebih umum lagi, pada akhir masa pakai objek.sumber
Saya menemukan penggunaan praktis lain
PhantomReferences
di kelas LeakDetector dari Jetty.Jetty menggunakan
LeakDetector
kelas untuk mendeteksi apakah kode klien memperoleh sumber daya tetapi tidak pernah melepaskannya danLeakDetector
kelas menggunakanPhantomReferences
untuk tujuan ini.sumber