आप एक WeakHashMap या WeakReference का उपयोग कब करेंगे?


163

कमजोर संदर्भों का उपयोग कुछ ऐसा है जिसे मैंने कभी लागू नहीं किया है इसलिए मैं यह पता लगाने की कोशिश कर रहा हूं कि उनके लिए उपयोग का मामला क्या है और कार्यान्वयन कैसे काम करेगा। आपको कब उपयोग करने की आवश्यकता है WeakHashMapया WeakReferenceइसका उपयोग कैसे किया गया था?



जवाबों:


96

मजबूत संदर्भों के साथ एक समस्या कैशिंग है, विशेष रूप से छवियों जैसी बहुत बड़ी संरचनाओं के साथ। मान लीजिए कि आपके पास एक एप्लिकेशन है जिसे उपयोगकर्ता द्वारा आपूर्ति की गई छवियों के साथ काम करना है, जैसे वेब साइट डिज़ाइन टूल मैं काम करता हूं। स्वाभाविक रूप से आप इन छवियों को कैश करना चाहते हैं, क्योंकि उन्हें डिस्क से लोड करना बहुत महंगा है और आप एक ही बार में मेमोरी में (संभवतः विशाल) छवि की दो प्रतियां होने की संभावना से बचना चाहते हैं।

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

कमजोर संदर्भों को समझना , एथन निकोलस


43
SoftReferences इस मामले में बेहतर नहीं होगा, अर्थात संदर्भ जो केवल तब एकत्र किए जाते हैं जब मेमोरी बाहर चलना शुरू होती है।
जेसप्रे सिप

मैं थोड़ा भ्रमित हूं ... मान लीजिए कि मेरे पास एक SWT इमेज कैश है। एसओ रिसोर्सेज को जारी करने के लिए डिस्पोज () विधि के जरिए SWT इमेज को डिसपोज किया जाना चाहिए। अगर मैं उन्हें स्टोर करने के लिए एक WeakHashMap का उपयोग करता हूं, तो वास्तव में जीसी ऑब्जेक्ट को डिस्पोज करेगा?
मार्कोलोप्स

2
@marcolopes जीसी किसी भी अन्य वस्तु पर एक अंतिम उपयोग करेगा। ऐसा लगता है कि जब आप ऐसा करते हैं तो SWT इसे पसंद नहीं करता है, इसलिए मुझे नहीं लगता कि आप ऑपरेटिंग सिस्टम संसाधनों का प्रबंधन कर सकते हैं WeakHashMap
याकूब क्रैल

@marcolopes, (मुझे लगता है कि आपके जीसी स्मृति को पुनः प्राप्त करने से पहले अंतिम रूप देने के लिए कॉल की गारंटी देता है।) यदि कैश कैशाइज़र में निपटान किया जाता है, तो सब ठीक है। यदि डिस्पोज़ कुछ ऐसा है जिसे आपको मैन्युअल रूप से कॉल करना है, तो या तो 1) क्लास का विस्तार करें और फाइनल में डिस्पोज़ करें, या 2) तदनुसार ट्रैक करने और चलाने के लिए फैंटमरेफेरेंस का उपयोग करें। विकल्प 2 बेहतर है (पुनरुत्थान के कीड़ों से बचा जाता है, और आपको दूसरे धागे पर निपटान चलाने की क्षमता देता है), लेकिन विकल्प 1 हेल्परक्लास के बिना लागू करना आसान है।
पेसियर


55

WeakReference बनाम SoftReference

स्पष्ट होने के लिए एक अंतर एक WeakReferenceऔर एक के बीच का अंतर है SoftReference

मूल रूप से एक WeakReferenceहो जाएगा जीसी d द्वारा JVM बेसब्री से, एक बार संदर्भित वस्तु नहीं है मुश्किल यह करने के लिए संदर्भ। SoftReferenceदूसरी ओर एक घ ऑब्जेक्ट, कचरा संग्राहक द्वारा तब तक छोड़ा जाएगा जब तक कि उसे वास्तव में मेमोरी को पुनः प्राप्त करने की आवश्यकता न हो।

एक कैश जहां मानों को अंदर रखा जाता है WeakReferenceवह बहुत बेकार होगा (एक में WeakHashMap, यह कुंजी है जो कमजोर संदर्भित हैं)। SoftReferencesजब आप एक कैश लागू करना चाहते हैं जो उपलब्ध स्मृति के साथ बढ़ सकता है और सिकुड़ सकता है, तब मूल्यों को लपेटने के लिए उपयोगी होते हैं।


4
"एक कैश जहां मानों को कमजोरियों के अंदर रखा जाता है वह बहुत बेकार होगा" मैं पूरी तरह से असहमत हूं।
थॉमस ईडिंग

5
@ ट्रिनिथिस - एर्म, मैं वास्तव में नहीं जानता कि क्या कहना है। एक कैश क्यों है जिसके मूल्य उस क्षण गायब हो जाते हैं जो आप उन्हें एक उपयोगी चीज नहीं बता रहे हैं , बिल्कुल?
Oxbow_lakes

4
संस्मरण जैसी किसी चीज़ के लिए, कैश जो अपने कैश्ड मूल्यों को शिथिल रखता है, उपयोगी हो सकता है।
थॉमस एडिंग

5
@ThomasEding मुझे अभी भी नहीं मिला है। जब कोई कैश उपयोगी लगता है, तब होता है जब उसके लिए कोई अन्य संदर्भ नहीं होता है ... यदि आपके पास इसके संदर्भ हैं, तो आपको कैश के लिए क्या चाहिए?
क्रंचर

2
@ थोमसाइडिंग, सॉफ्टएफ़ पर्यावरण को बताता है "इसे तब तक स्टोर करें जब तक आपके पास कोई मेमोरी न हो"। वीकेएफ़आर पर्यावरण को बताता है "जीसी के चलने तक इसे स्टोर करें"। कमजोरी के लिए स्पष्ट रूप से कोई उपयोग का मामला नहीं है जब तक कि आप स्वयं जीसी को डीबगिंग / प्रोफाइलिंग नहीं कर रहे हैं। यदि आप स्मृति-संवेदी कैश चाहते हैं, तो सॉफ्टएफ़ का उपयोग करें। यदि आप कैश नहीं चाहते हैं, तो इसे कैश न करें! कहां से आता है कमजोर?
पचेरियर

30

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

यदि आप WeakHashMapइसके बजाय उपयोग करते हैं तो ऑब्जेक्ट आपके नक्शे को छोड़ देंगे जैसे ही वे आपके बाकी प्रोग्राम द्वारा उपयोग नहीं किए जाते हैं, जो वांछित व्यवहार है।

java.awt.Component1.4.2 और 1.5 के बीच JRE में बदलाव लाने के लिए मुझे कुछ डेटा जोड़ने के लिए ऐसा करना पड़ा , मैं इसे हर उस घटक को उप-वर्ग द्वारा तय कर सकता था जिसे मैं इंट (इंटेक , ....) चाह रहा था JButton, लेकिन यह बहुत ज्यादा था बहुत कम कोड के साथ आसान।JFrameJPanel


1
WeakHashMap को कैसे पता चलता है "वे अब आपके कार्यक्रम के बाकी हिस्सों द्वारा उपयोग नहीं किए जाते हैं"?
विनोथ कुमार CM

2
एक कमजोर हैमैप अपनी कुंजियों के लिए कमजोर संदर्भों का उपयोग करता है। जब किसी वस्तु को केवल कमजोर संदर्भों के माध्यम से संदर्भित किया जाता है, तो कचरा संग्रहकर्ता कमजोर संदर्भ (इस मामले में WeaHashMap) के मालिक को 'सूचित' करेगा। मैं WavReferences और ReferenceQueues पर javadocs में पढ़ूंगा कि यह समझने के लिए कि ये ऑब्जेक्ट कचरा संग्रहकर्ता के साथ कैसे बातचीत करते हैं।
ल्यूक

1
धन्यवाद ल्यूक, क्या आप विवरण के लिए सरल कोड प्रदान कर सकते हैं?
उबला हुआ पानी

इस प्रकार, कमजोरता केवल जावा में समझ में आता है क्योंकि जावा की क्वर्की एपीआई जहां कुछ वर्गों को बढ़ाया नहीं जा सकता है।
पेसियर

22

के लिए एक और उपयोगी मामला है WeakHashMapऔर WeakReferenceएक श्रोता रजिस्ट्री कार्यान्वयन है

जब आप कुछ बनाते हैं जो कुछ घटनाओं को सुनना चाहते हैं, तो आमतौर पर आप एक श्रोता को पंजीकृत करते हैं, जैसे

manager.registerListener(myListenerImpl);

यदि managerआपका श्रोता एक के साथ भंडार करता है WeakReference, तो इसका मतलब है कि आपको रजिस्टर को हटाने की आवश्यकता नहीं है, manager.removeListener(myListenerImpl)क्योंकि यह आपके श्रोता या आपके घटक द्वारा श्रोता को अनुपलब्ध होते ही स्वचालित रूप से हटा दिया जाएगा।

बेशक, आप अभी भी अपने श्रोता को मैन्युअल रूप से हटा सकते हैं, लेकिन यदि आप इसे नहीं भूलते हैं या इसे भूल जाते हैं, तो यह मेमोरी रिसाव का कारण नहीं होगा, और यह आपके श्रोता को कचरा एकत्र करने से नहीं रोकेगा।

WeakHashMapचित्र में कहाँ आता है ?

श्रोता रजिस्ट्री जो पंजीकृत श्रोताओं को संग्रहीत करने के लिए व्हाट्सएप करता है, को WeakReferenceइन संदर्भों को संग्रहीत करने के लिए एक संग्रह की आवश्यकता होती है। WeakHashSetकेवल मानक जावा लाइब्रेरी में कोई कार्यान्वयन नहीं है WeakHashMapलेकिन हम पहले वाले की कार्यक्षमता को "लागू" करने के लिए बाद वाले का उपयोग आसानी से कर सकते हैं:

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

इसके साथ listenerSetएक नए श्रोता को पंजीकृत करने के लिए आपको बस इसे सेट में जोड़ना होगा, और भले ही इसे स्पष्ट रूप से हटाया न जाए, अगर श्रोता को अब संदर्भित नहीं किया जाता है, तो यह JVM द्वारा स्वचालित रूप से हटा दिया जाएगा।


10
श्रोता सूची के लिए कमजोरHashSets का उपयोग करने में समस्या यह है कि रजिस्टर () में बनाए गए अनाम श्रोता उदाहरण आसानी से खो जाएंगे, जो उपयोगकर्ता द्वारा अप्रत्याशित होगा। इसके बजाय प्रबंधकों से श्रोताओं के लिए मजबूत संदर्भ रखना सुरक्षित है, और इसके बजाय सही काम करने के लिए फोन करने वाले पर भरोसा करें।
गुनानरेश डिक

श्रोता रजिस्ट्री कार्यान्वयन के लिए: सभी पंजीकृत श्रोताओं को अगले जीसी किक पर एकत्र / नष्ट कर दिया जाएगा? उदाहरण के लिए, सभी श्रोता ऑनर्सोमिंगहैप्ड () विधि से फायरिंग करते समय, यदि जीसी किक करता है तो क्या होता है?
कालाकार

@icza, मुझे विश्वास नहीं हो रहा है कि लोग अब भी इस मिथक को भुना रहे हैं। यह पूरी तरह से गलत जवाब है। WeakHashMapजब भी आपको HashMapवस्तुओं की आवश्यकता हो, तब आप एक और उपयोगी मामला कह सकते हैं। तो वाह आपको मैन्युअल रूप से कभी भी hashmap.remove नहीं करना है क्योंकि obj के दायरे से बाहर होने के बाद आइटम स्वचालित रूप से हटा दिए जाते हैं! सचमुच जादू! इस तरह के बदसूरत जादू हैक एक पूर्ण चेहरा है
पेसियर

3
@ स्पेसर: मैंने जावास्क्रिप्ट में अन्य टिप्पणियों से आपके लिंक का अनुसरण किया है, यहां सभी तरह से नीचे उतरें, और अभी भी काफी समझ में नहीं आया कि वीकेप के साथ श्रोता रजिस्ट्री कार्यान्वयन एक मिथक क्यों है। उदाहरण के लिए, यदि WebSocket क्लाइंट रजिस्ट्री सेवा के माध्यम से उन पर कुछ श्रोताओं से बंधे होने चाहिए, तो WeakMap में कुंजी के रूप में सॉकेट ऑब्जेक्ट्स को संग्रहीत करना तर्कसंगत लगता है (कनेक्शन बंद होने के बाद उन्हें मेमोरी में लटकने से रोकने के लिए, त्रुटि पर) और सक्षम होने के नाते जरूरत पड़ने पर उनके सभी श्रोताओं को पुनः प्राप्त करने के लिए। इसलिए, क्या आप कृपया बता सकते हैं कि उस दृष्टिकोण में क्या गलत है?
क्षतिग्रस्त

1
@ स्पेसर मैं भी आपकी आपत्ति को समझने में विफल हूं। प्रकाशित-सदस्यता या ईवेंट बस परिदृश्य में, कमजोर संदर्भों का एक संग्रह मेरे लिए सही अर्थ रखता है। सब्सक्राइबिंग ऑब्जेक्ट को औपचारिक रूप से अनसब्सक्राइब करने की आवश्यकता के बिना स्कोप और हेड टू कचरा कलेक्शन से बाहर जाने की अनुमति है। सदस्यता समाप्त करने की प्रक्रिया विशेष रूप से जटिल हो सकती है यदि किसी तीसरे पक्ष की वस्तु सदस्यता के बिना प्रारंभिक सदस्यता के लिए जिम्मेदार थी। WeakReferenceबहुत से संग्रह कोड आधार को सरल बनाते हैं और सदस्यता समाप्त करने से संबंधित अनावश्यक बग से बचते हैं। क्या नकारात्मकता?
तुलसी बोरक

5

यह ब्लॉग पोस्ट दोनों वर्गों के उपयोग को प्रदर्शित करता है: जावा: एक आईडी पर सिंक्रनाइज़ करना । उपयोग कुछ इस तरह से होता है:

private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();

public void performTask(String resourceId) {
    IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
    synchronized (mutext) {
        // look up the resource and do something with it
    }
}

IdMutextProvider आईडी-आधारित ऑब्जेक्ट को सिंक्रनाइज़ करने के लिए प्रदान करता है। आवश्यकताएं हैं:

  • समतुल्य आईडी के समवर्ती उपयोग के लिए उसी वस्तु का संदर्भ वापस करना चाहिए
  • अलग-अलग आईडी के लिए एक अलग ऑब्जेक्ट वापस करना होगा
  • कोई रिलीज़ तंत्र (ऑब्जेक्ट प्रदाता को वापस नहीं किए जाते हैं)
  • रिसाव नहीं होना चाहिए (अप्रयुक्त वस्तुएं कचरा संग्रहण के लिए योग्य हैं)

यह प्रकार के आंतरिक संग्रहण मानचित्र का उपयोग करके प्राप्त किया जाता है:

WeakHashMap<Mutex, WeakReference<Mutex>>

ऑब्जेक्ट कुंजी और मूल्य दोनों है। जब मानचित्र के बाहरी कुछ भी वस्तु के लिए एक कठिन संदर्भ नहीं है, तो यह कचरा एकत्र किया जा सकता है। मानचित्र में मानों को कठिन संदर्भों के साथ संग्रहीत किया जाता है, इसलिए स्मृति रिसाव को रोकने के लिए मूल्य को WeakReference में लपेटा जाना चाहिए । यह अंतिम बिंदु जावदोक में शामिल है ।


3

यदि आप उदाहरण के लिए एक निश्चित वर्ग से बनी सभी वस्तुओं का ट्रैक रखना चाहते हैं। अभी भी इन वस्तुओं को कचरा एकत्र करने की अनुमति देने के लिए, आप वस्तुओं के बजाय वस्तुओं के कमजोर संदर्भों की एक सूची / नक्शा रखते हैं।

अब अगर कोई मुझे प्रेत-संदर्भ समझा सकता है, तो मुझे खुशी होगी ...


2
एक उपयोग: PhantomReferences आपको यह निर्धारित करने की अनुमति देता है कि कोई ऑब्जेक्ट मेमोरी से निकाला गया था या नहीं। वे वास्तव में यह निर्धारित करने का एकमात्र तरीका हैं। ( weblogs.java.net/blog/enicholas/archive/2006/05/… )
याकूब क्राल

वास्तव में इसे तब तक नहीं हटाया जाता जब तक आप इसे स्पष्ट रूप से स्पष्ट नहीं करते। "नरम और कमजोर संदर्भों के विपरीत, प्रेत संदर्भों को कचरा कलेक्टर द्वारा स्वचालित रूप से साफ नहीं किया जाता है क्योंकि वे एन्क्यूटेड होते हैं। एक वस्तु जो प्रेत संदर्भों के माध्यम से पहुंच योग्य होती है, वह तब तक बनी रहेगी जब तक कि इस तरह के सभी संदर्भ साफ नहीं हो जाते या स्वयं अप्राप्य नहीं हो जाते।"
jontro

@ जोंरो, लेकिन यह पहले से ही अंतिम रूप दे दिया गया है , सभी सदस्य चले गए हैं। प्रभावी रूप से, यह एक खाली ओब्ज है। देखें stackoverflow.com/q/7048767/632951
Pacerier

3

जैसा कि ऊपर कहा गया है, जब तक एक मजबूत संदर्भ मौजूद है, तब तक कमजोर संदर्भ आयोजित किए जाते हैं।

उदाहरण का उपयोग श्रोताओं के अंदर WeakReference का उपयोग करना होगा, ताकि श्रोता अपने लक्ष्य वस्तु के मुख्य संदर्भ के चले जाने के बाद अब सक्रिय न हों। ध्यान दें कि इसका मतलब यह नहीं है कि WeakReference को श्रोताओं की सूची से हटा दिया गया है, सफाई अभी भी आवश्यक है, लेकिन प्रदर्शन किया जा सकता है, उदाहरण के लिए, निर्धारित समय पर। इससे सुनी गई वस्तु को मजबूत संदर्भ धारण करने से रोकने का प्रभाव पड़ता है और अंततः मेमोरी ब्लोट का स्रोत बन जाता है। उदाहरण: स्विंग GUI घटक एक मॉडल का संदर्भ देते हैं जिसमें खिड़की की तुलना में लंबा जीवनचक्र होता है।

जैसा कि ऊपर वर्णित श्रोताओं के साथ खेलने के दौरान हमने तेजी से महसूस किया कि उपयोगकर्ता के दृष्टिकोण से वस्तुओं को "तुरंत" एकत्र किया जाता है।


धन्यवाद उपयोगी उत्तर। लेकिन मैं सोच रहा था, उस मामले में, श्रोताओं को दृढ़ता से पंजीकृत (संदर्भित) किया जाना चाहिए?
कालाकार

यह जवाब पूरी तरह से गलत है। विस्तार: stackoverflow.com/questions/154724/…
Pacerier

@ स्पेसर - WeakReferencesआपकी टिप्पणी के लिए पूरी तरह से गलत है!

2

WeakReferences के लिए मेरे पास एक वास्तविक विश्व उपयोग है यदि आपके पास एक एकल, बहुत बड़ी वस्तु है जो शायद ही कभी उपयोग की जाती है। आप इसे स्मृति में नहीं रखना चाहते जब यह आवश्यक नहीं है; लेकिन, यदि किसी अन्य थ्रेड को समान ऑब्जेक्ट की आवश्यकता है, तो आप उनमें से दो को स्मृति में नहीं चाहते हैं। आप कहीं भी वस्तु का कमजोर संदर्भ रख सकते हैं, और इसका उपयोग करने वाले तरीकों में कठिन संदर्भ; जब दोनों विधि समाप्त हो जाती है, तो वस्तु को एकत्र किया जाएगा।


1
यह एक नरमी है, कमजोर नहीं। देखें stackoverflow.com/a/155492/632951
4


-1

आप एक्सपेंसिव ऑब्जेक्ट निर्माण के लिए रिसोर्स-फ्री कैशिंग लागू करने के लिए weakhashmap का उपयोग कर सकते हैं।

लेकिन ध्यान दें कि यह उत्परिवर्तनीय वस्तुओं के लिए वांछनीय नहीं है। मैंने इसे टेक्स्ट-सर्च इंजन को क्वेरी परिणामों (जो कि लगभग 400 ms निष्पादित करने के लिए लेता है) को कैश करने के लिए उपयोग किया, जो शायद ही कभी अपडेट किया जाता है।


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