क्या आपने कभी किसी प्रोजेक्ट में PhantomReference का इस्तेमाल किया है?


89

केवल एक चीज जिसके बारे PhantomReferenceमें मुझे पता है,

  • यदि आप इसकी get()विधि का उपयोग करते हैं , तो यह हमेशा वापस आएगा nullऔर वस्तु नहीं। इसका क्या उपयोग है?
  • उपयोग करके PhantomReference, आप यह सुनिश्चित करते हैं कि ऑब्जेक्ट को finalizeविधि से पुनर्जीवित नहीं किया जा सकता है ।

लेकिन इस अवधारणा / वर्ग का उपयोग क्या है?

क्या आपने कभी अपने किसी प्रोजेक्ट में इसका इस्तेमाल किया है या क्या आपके पास कोई उदाहरण है जहां हमें इसका इस्तेमाल करना चाहिए?


इसके अलावा stackoverflow.com/a/9827686/632951
Pacerier

जैसा कि आप एक प्रेत बाधा का संदर्भ नहीं पा सकते हैं, इसका पूरा मिथ्या नाम: इसे बुलाया जाना चाहिए FakeReferenceया NonReference
पेसियर

यहाँ कोड के साथ अनॉथेर थ्रेड है: stackoverflow.com/q/43311825/632951
पचेरियर

जवाबों:


47

मैंने ऑब्जेक्ट निर्माण और विनाश की निगरानी के लिए PhantomReferenceएक सरलीकृत, बहुत विशिष्ट प्रकार के मेमोरी प्रोफाइलर में उपयोग किया। मुझे उन्हें विनाश का ट्रैक रखने की आवश्यकता थी। लेकिन दृष्टिकोण आउट-डेटेड है। (यह 2004 में J2SE 1.4 को लक्षित करते हुए लिखा गया था।) प्रोफेशनल प्रोफाइलिंग टूल बहुत अधिक शक्तिशाली और विश्वसनीय हैं और JMX या एजेंटों और JVMTI जैसे नए जावा 5 फीचर्स का उपयोग इसके लिए भी किया जा सकता है।

PhantomReferences (हमेशा संदर्भ कतार के साथ प्रयोग किया जाता है) बेहतर होता है, finalizeजिसमें कुछ समस्याएं होती हैं और इसलिए इससे बचना चाहिए। मुख्य रूप से वस्तुओं का फिर से पहुंच बनाना। इसे अंतिम अभिभावक मुहावरे के साथ टाला जा सकता है (-> 'प्रभावी जावा' में अधिक पढ़ें)। इसलिए वे नए फाइनल भी हैं ।

इसके अलावा, PhantomReferenceएस

जब आप किसी ऑब्जेक्ट को स्मृति से हटा दिया गया था, तो आप वास्तव में निर्धारित करने की अनुमति देते हैं। वे वास्तव में यह निर्धारित करने का एकमात्र तरीका हैं। यह आम तौर पर उपयोगी नहीं है, लेकिन बड़ी छवियों में हेरफेर करने जैसी कुछ बहुत विशिष्ट परिस्थितियों में काम आ सकता है: यदि आप यह सुनिश्चित करने के लिए जानते हैं कि एक छवि कचरा एकत्र की जानी चाहिए, तो आप तब तक इंतजार कर सकते हैं जब तक कि यह वास्तव में अगली छवि को लोड करने का प्रयास न हो। , और इसलिए घबड़ाया हुआ OutOememoryError कम संभावना है। ( एनिचोल से उद्धृत )

और जैसा कि Psd ने पहले लिखा था, रोएडी ग्रीन के पास संदर्भों का एक अच्छा सारांश है


21

जावा शब्दावली से एक सामान्य डिस-अप टेबल विवरण

पाठ्यक्रम में से कौन सा प्रेत प्रलेखन से मेल खाता है :

प्रेत संदर्भ वस्तुएं, जिन्हें कलेक्टर के बाद निर्धारित किया जाता है कि उनके संदर्भों को पुनः प्राप्त किया जा सकता है। जावा अंतिमकरण तंत्र के साथ संभव से अधिक लचीले तरीके से पूर्व-मृत्यु की सफाई क्रियाओं का समय निर्धारण के लिए प्रेत संदर्भों का सबसे अधिक उपयोग किया जाता है।

और अंतिम लेकिन कम से कम नहीं, सभी गौरी विवरण ( यह एक अच्छी तरह से पढ़ा गया है ): जावा संदर्भ ऑब्जेक्ट्स (या मैं कैसे चिंता करना बंद करना और प्यार करना सीखता हूं)

खुश कोडिंग। (लेकिन इस सवाल का जवाब देने के लिए, मैंने कभी केवल WeakReferences का उपयोग किया है।)


Btw, उस लेख के बारे में एक सवाल। PhantomReference पर अनुभाग में, वह उन दो तालिकाओं के माध्यम से वस्तुओं को जोड़ने के लिए एक मजबूत संदर्भ रखता है। इसका अर्थ है कि कनेक्शन कभी भी अगम्य नहीं होंगे (यह मानकर कि पूल का उदाहरण कभी भी अप्राप्य नहीं हो सकता है)। तो इसी PhantomReferences कभी भी सही नहीं होगा? या क्या मैं कुछ न कुछ भूल रहा हूं?
श्राइन १।

1
वाह, kdgregory का वह लेख +10
Pacerier

14

प्रेत संदर्भ उपयोग की महान व्याख्या :

प्रेत संदर्भ किसी वस्तु को स्मृति से हटाने का सुरक्षित तरीका है। उदाहरण के लिए, एक एप्लिकेशन पर विचार करें जो बड़ी छवियों से संबंधित है। मान लीजिए कि हम एक बड़ी छवि को मेमोरी में लोड करना चाहते हैं जब बड़ी छवि पहले से ही मेमोरी में है जो एकत्र किए गए कचरे के लिए तैयार है। ऐसे मामले में, हम इंतजार करना चाहते हैं जब तक कि नया लोड करने से पहले पुरानी छवि एकत्र न हो जाए। यहां, प्रेत संदर्भ लचीला और सुरक्षित रूप से चुनने का विकल्प है। पुरानी छवि ऑब्जेक्ट को अंतिम रूप देने के बाद, संदर्भ चित्र में पुरानी छवि का संदर्भ दिया जाएगा। उस संदर्भ को प्राप्त करने के बाद, हम नई छवि को मेमोरी में लोड कर सकते हैं।


12

मुझे एक व्यावहारिक और उपयोगी उपयोग का मामला मिला, PhantomReferenceजो org.apache.commons.io.FileCleaningTrackerकॉमन्स-आईओ परियोजना में है। FileCleaningTrackerभौतिक फ़ाइल हटा देगा जब उसका मार्कर ऑब्जेक्ट कचरा एकत्र किया जाएगा।
नोट करने के लिए कुछ वह Trackerवर्ग है जो वर्ग का विस्तार करता है PhantomReference


5

यह जावा 9 के साथ होना चाहिए! इसके बजाय का
उपयोग करें java.util.Cleaner! (या sun.misc.Cleanerपुराने JRE पर)

मूल पोस्ट:


मैंने पाया कि PhantomReferences के उपयोग में अंतिम विधियों के रूप में लगभग समान ही नुकसान होते हैं (लेकिन एक बार ठीक होने के बाद कम समस्याएं)। मैंने Java 8 के लिए एक छोटा सा समाधान (PhantomReferences का उपयोग करने के लिए एक बहुत छोटा ढांचा) लिखा है। यह ऑब्जेक्ट को हटाए जाने के बाद कॉलबैक के रूप में लैम्बडा एक्सप्रेशन का उपयोग करने की अनुमति देता है। आप आंतरिक संसाधनों के लिए कॉलबैक पंजीकृत कर सकते हैं जिन्हें बंद किया जाना चाहिए। इसके साथ मुझे एक समाधान मिला है जो मेरे लिए काम करता है क्योंकि यह इसे और अधिक व्यावहारिक बनाता है।

https://github.com/claudemartin/java-cleanup

यहां एक छोटा उदाहरण दिखाया गया है कि कॉलबैक कैसे पंजीकृत होता है:

  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);
    }

और फिर ऑटो-क्लोज़ के लिए और भी सरल तरीका है, जो ऊपर के समान ही कर रहा है:

this.registerAutoClose(this.resource);

अपने सवालों के जवाब देने के लिए:

[फिर इसका क्या उपयोग है]

आप किसी ऐसी चीज़ को साफ़ नहीं कर सकते जो मौजूद नहीं है। लेकिन इसके पास ऐसे संसाधन हो सकते हैं जो अभी भी मौजूद हैं और उन्हें साफ करने की आवश्यकता है ताकि उन्हें हटाया जा सके।

लेकिन इस अवधारणा / वर्ग का उपयोग क्या है?

डिबगिंग / लॉगिंग के अलावा किसी भी प्रभाव के साथ कुछ भी करना जरूरी नहीं है। या शायद आँकड़ों के लिए। मैं इसे जीसी से एक अधिसूचना सेवा की तरह अधिक देखता हूं। आप ऑब्जेक्ट को हटाए जाने के बाद अप्रासंगिक हो जाने वाले एकत्रित डेटा को निकालने के लिए भी इसका उपयोग करना चाहते हैं (लेकिन शायद इसके लिए बेहतर समाधान हैं)। उदाहरण अक्सर डेटाबेस कनेक्शन को बंद करने का उल्लेख करते हैं, लेकिन मैं यह नहीं देखता कि यह इतना अच्छा विचार कैसे है क्योंकि आप लेनदेन के साथ काम नहीं कर सकते। एक एप्लीकेशन फ्रेमवर्क इसके लिए एक बेहतर समाधान प्रदान करेगा।

क्या आपने कभी अपने किसी प्रोजेक्ट में इसका उपयोग किया है, या क्या आपके पास कोई उदाहरण है जहां हमें इसका उपयोग करना चाहिए? या यह अवधारणा सिर्फ साक्षात्कार बिंदु के लिए बनाई गई है;)

मैं इसका इस्तेमाल ज्यादातर सिर्फ लॉगिंग के लिए करता हूं। इसलिए मैं हटाए गए तत्वों का पता लगा सकता हूं और देख सकता हूं कि जीसी कैसे काम करता है और इसे ट्विक किया जा सकता है। मैं इस तरह से कोई महत्वपूर्ण कोड नहीं चलाऊंगा। यदि किसी चीज़ को बंद करने की आवश्यकता है, तो इसे एक कोशिश के साथ-संसाधन-कथन में किया जाना चाहिए। और मैं इसे यूनिट परीक्षणों में उपयोग करता हूं, यह सुनिश्चित करने के लिए कि मेरे पास कोई मेमोरी लीक नहीं है। ठीक उसी तरह जिस तरह से जोंतेज करता है। लेकिन मेरा समाधान थोड़ा और सामान्य है।


हां, मेरे समाधान "जावा-सफाई" की तरह। दोनों अमूर्त हैं, इसलिए आपको उनसे सीधे निपटने की आवश्यकता नहीं है।
क्लॉड मार्टिन

3

मैंने जांच के लिए एक इकाई परीक्षण में एक प्रेत परीक्षण का उपयोग किया था ताकि यह पता चल सके कि परीक्षण के तहत कोड किसी वस्तु के लिए अनैच्छिक संदर्भ नहीं रखता है। ( मूल कोड )

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>());
}
}

और परीक्षण :

@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>");
    }
}

2

WeakReferenceजहां PhantomReferenceअधिक उपयुक्त हो, वहां उपयोग करना आम है । यह WeakReferenceकचरे के संग्रहकर्ता द्वारा साफ / संलग्न किए जाने के बाद वस्तुओं को फिर से जीवित करने में सक्षम होने की कुछ समस्याओं से बचा जाता है । आमतौर पर अंतर कोई फर्क नहीं पड़ता क्योंकि लोग मूर्खतापूर्ण बुर्ज नहीं खेल रहे हैं।

का उपयोग करते हुए PhantomReference, क्योंकि आप का नाटक नहीं कर सकते हैं कि थोड़ा अधिक दखल हो जाता है getविधि काम करता है। उदाहरण के लिए, आप नहीं लिख सकते Phantom[Identity]HashMap


IdentityHashMap <PhantomReference> एक IdentityHashMap के लिए वास्तव में उपयुक्त स्थानों में से एक है। ध्यान दें कि मजबूत संदर्भ PhantomReference पर रखा गया है, लेकिन संदर्भ नहीं

क्या आपका वास्तव में मतलब है कि कमजोर संदर्भों के लिए, अंतिम रूप से obj को फिर से बनाया जा सकता है? weakref.getलौट सकता है null, और फिर बाद में, यह अभी भी obj वापस करने में सक्षम है?
पेसियर

@ स्पेसर finalizeवस्तु को फिर से नहीं बनाता है। यह एक के बाद जोरदार पहुंच योग्य फिर वस्तु बना सकते हैं WeakReferenceरिटर्न nullसे getऔर कतारबद्ध कर रहा है। / (user166390: जैसा कि संदर्भ के लक्ष्य पर दिए गए नक्शे में है, जैसा कि WeakHashMapनहीं, संदर्भ का एक पहचान मानचित्र जो ठीक है।)
टॉम हैटिन - 23

1

यदि आप इसके प्राप्त () विधि का उपयोग करते हैं तो यह हमेशा अशक्त रहेगा, न कि वस्तु। [फिर इसका क्या उपयोग है]

कॉल करने की उपयोगी विधियाँ (बजाय get()) होगी isEnqueued()या referenceQueue.remove()। आप इन तरीकों को कुछ कार्रवाई करने के लिए कहेंगे जो कि ऑब्जेक्ट के कचरा संग्रह के अंतिम दौर में होने की आवश्यकता है।

चारों ओर पहली बार तब होता है जब ऑब्जेक्ट की finalize()विधि को बुलाया जाता है, इसलिए आप वहां समापन हुक भी लगा सकते हैं। हालाँकि, जैसा कि अन्य लोगों ने कहा है, संभवतः सफाई के प्रदर्शन के अधिक निश्चित तरीके हैं या जो कुछ भी करने की आवश्यकता होती है, वह वस्तु के जीवन के अंत से पहले और बाद में कचरा संग्रह करने की आवश्यकता होती है।


1

मुझे जेट्टी के लीकेडेक्टर वर्ग PhantomReferencesमें एक और व्यावहारिक उपयोग मिला ।

जेट्टी LeakDetectorवर्ग का पता लगाने के लिए वर्ग का उपयोग करता है यदि क्लाइंट कोड एक संसाधन प्राप्त करता है लेकिन इसे कभी जारी नहीं करता है और LeakDetectorवर्ग PhantomReferencesइस उद्देश्य के लिए उपयोग करता है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.