2008-11-07 7 views
27

क्या सिंगलटन ऑब्जेक्ट्स जो उदाहरण/संदर्भ काउंटर का उपयोग नहीं करते हैं उन्हें सी ++ में मेमोरी लीक माना जाना चाहिए?सिंगलटन विनाशक

एक काउंटर के बिना जो सिंगलटन उदाहरण को स्पष्ट रूप से हटाने के लिए कहता है जब गिनती शून्य होती है, ऑब्जेक्ट कैसे हटाया जाता है? जब एप्लिकेशन समाप्त हो जाता है तो क्या यह ओएस द्वारा साफ किया जाता है? क्या होगा यदि सिंगलटन ने ढेर पर स्मृति आवंटित की थी?

संक्षेप में, क्या मुझे सिंगलटन के विनाशक को फोन करना होगा या क्या मैं आवेदन समाप्त होने पर इसे साफ़ करने पर भरोसा कर सकता हूं?

उत्तर

14

आप ऑपरेटिंग सिस्टम द्वारा इसे साफ करने पर भरोसा कर सकते हैं।

यह कहा गया है कि, यदि आप कचरे में हैं तो विनाशकों के बजाए फाइनलाइजर्स के साथ एकत्रित भाषा के साथ आप एक सुंदर शट डाउन प्रक्रिया चाहते हैं जो आपके सिंगलेट्स को सीधे बंद कर सकती है ताकि सिस्टम संसाधनों का उपयोग करने पर वे किसी भी महत्वपूर्ण संसाधन को मुक्त कर सकें जो केवल एप्लिकेशन को समाप्त करके सही ढंग से साफ नहीं किया जाएगा। ऐसा इसलिए है क्योंकि अंतिम भाषाएं अधिकांश भाषाओं में 'सर्वश्रेष्ठ प्रयास' आधार पर चलती हैं। दूसरी ओर वहां बहुत कम संसाधन हैं जिन्हें इस तरह की विश्वसनीयता की आवश्यकता है। फाइल हैंडल, मेमोरी इत्यादि सभी ओएस पर वापस ध्यान दिए बिना साफ-सफाई करते हैं।

यदि आप एक सिंगलटन का उपयोग कर रहे हैं जो आलसी आवंटित (यानी ट्रिपल-चेक लॉक मुहावरे के साथ) सी ++ जैसी भाषा में अंतिम रूपकों के बजाय असली विनाशकों के साथ है, तो आप प्रोग्राम शट डाउन के दौरान अपने विनाशक पर भरोसा नहीं कर सकते हैं। यदि आप एक स्थिर आवृत्ति का उपयोग कर रहे हैं तो कुछ बिंदु पर मुख्य पूर्ण होने के बाद विनाशक चलाएगा।

भले ही, प्रक्रिया समाप्त होने पर, सभी मेमोरी ऑपरेटिंग सिस्टम पर वापस आती हैं।

0

आपकी प्रक्रिया द्वारा आवंटित कोई भी ढेर स्मृति और मुक्त नहीं (हटाया गया) ओएस द्वारा पुनः दावा किया जाएगा। यदि आप सिंगलटन के सबसे आम कार्यान्वयन का उपयोग कर रहे हैं, जो स्थैतिक चर का उपयोग करता है, तो यह आपके आवेदन की समाप्ति पर भी साफ हो जाएगा।

* इसका मतलब यह नहीं है कि आपको नए-नए पॉइंटर्स के आसपास जाना चाहिए और उन्हें कभी साफ नहीं करना चाहिए।

1

singleton आपके ऑब्जेक्ट का एक उदाहरण होगा। यही कारण है कि इसे काउंटर की आवश्यकता नहीं है। यदि यह आपके आवेदन की लंबाई के लिए अस्तित्व में है तो डिफ़ॉल्ट विनाशक ठीक होगा। स्मृति समाप्त हो जाएगी, किसी भी मामले में, प्रक्रिया समाप्त होने पर ऑपरेटिंग सिस्टम द्वारा पुनः दावा किया जाएगा।

3

साझा यादों को छोड़कर किसी भी तरह का आवंटन, प्रक्रिया समाप्त होने पर ऑपरेटिंग सिस्टम द्वारा स्वचालित रूप से साफ़ हो जाती है। इसलिए आपको सिंगलटन विनाशक को स्पष्ट रूप से कॉल नहीं करना चाहिए। दूसरे शब्दों कोई लीक ... में

इसके अलावा मेयर्स 'सिंगलटन की तरह एक ठेठ सिंगलटन कार्यान्वयन केवल सुरक्षित पहली कॉल पर प्रारंभ दौरान थ्रेड नहीं है, लेकिन यह भी आवेदन बाहर निकलता है (नाशक है जब समाप्त सुशोभित करने की गारंटी लागू)।

वैसे भी आवेदन एक यूनिक्स संकेत भेजा गया हो तो (यानी: SIGTERM या SIGHUP) डिफ़ॉल्ट व्यवहार स्थिर आवंटित वस्तुओं (एकमात्र) का विनाशकर्ता बुला बिना प्रक्रिया समाप्त करने के लिए है। इन संकेतों के लिए इस मुद्दे को दूर करने के लिए एक हैंडलर कॉलिंग से बाहर निकलना संभव है, या निकास का निपटान ऐसे हैंडलर - signal(SIGTERM,exit);

+0

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

1

एक रिसाव की आपकी परिभाषा पर निर्भर करता है।अनबाउंड मेमोरी वृद्धि मेरी पुस्तक में एक रिसाव है, एक सिंगलटन अनबाउंड नहीं है। यदि आप संदर्भ गिनती प्रदान नहीं करते हैं, तो आप जानबूझकर उदाहरण को जीवित रखते हैं। एक दुर्घटना नहीं, एक रिसाव नहीं।

आपके सिंगलटन रैपर के विनाशक को उदाहरण को हटाना चाहिए, यह स्वचालित नहीं है। अगर यह सिर्फ स्मृति आवंटित करता है और कोई ओएस संसाधन नहीं है, तो कोई बात नहीं है।

11

आपको अपनी सभी वस्तुओं को स्पष्ट रूप से साफ़ करना चाहिए। आपके लिए साफ करने के लिए कभी भी ओएस पर भरोसा न करें।

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

यह एक स्मृति लीकिंग मुद्दा नहीं है- मुद्दा यह है कि आप स्मृति के अलावा अन्य संसाधनों को लीक कर सकते हैं जिन्हें आसानी से पुनर्प्राप्त नहीं किया जा सकता है।

+0

+1 वास्तव में, लेकिन कुछ सिंगलेट्स जब बाहर निकलते हैं तो विनाशक की कॉल सुनिश्चित करते हैं। –

+1

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

9

प्रत्येक भाषा और पर्यावरण अलग-अलग होगा, हालांकि मैं @ एरॉन फिशर से सहमत हूं कि एक सिंगलटन प्रक्रिया की अवधि के लिए मौजूद है।

सी ++ के उदाहरण में, एक ठेठ सिंगलटन मुहावरा का उपयोग कर:

Singleton &get_singleton() 
{ 
    static Singleton singleton; 
    return singleton; 
} 

सिंगलटन उदाहरण पहली बार समारोह में कहा जाता है निर्माण किया जाएगा, और एक ही उदाहरण यह नाशक वैश्विक स्थिर दौरान कहा जाता है होगा कार्यक्रम बंद करने पर विनाशक चरण।

20

अक्सर, "यह निर्भर करता है"। नाम के योग्य किसी भी ऑपरेटिंग सिस्टम में, जब आपकी प्रक्रिया निकलती है, तो प्रक्रिया के भीतर स्थानीय रूप से उपयोग की जाने वाली सभी मेमोरी और अन्य संसाधनों को रिलीज़ किया जाएगा। आपको बस इसके बारे में चिंता करने की ज़रूरत नहीं है।

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

आरएआईआई आपकी मदद करेंगे। आप इस तरह से एक परिदृश्य है:

class Tempfile 
{ 
Tempfile() {}; // creates a temporary file 
virtual ~Tempfile(); // close AND DELETE the temporary file 
}; 

Tempfile &singleton() 
{ 
    static Tempfile t; 
    return t; 
} 

... तो आप को आश्वस्त किया जा सकता है कि अपने अस्थायी फ़ाइल बंद कर दिया और फिर भी अपने आवेदन बाहर निकलता है हटा दिया जाएगा। However, this is NOT thread-safe, and the order of object deletion may not be what you expect or require.

हालांकि, अगर आपका सिंगलटन इस

Tempfile &singleton() 
{ 
    static Tempfile *t = NULL; 
    if (t == NULL) 
    t = new Tempfile(); 
    return *t; 
} 

तरह कार्यान्वित किया जाता है ... तो आप एक अलग स्थिति है। आपके tempfile द्वारा उपयोग की जाने वाली स्मृति को पुनः दावा किया जाएगा, लेकिन फ़ाइल को हटाया नहीं जाएगा क्योंकि विनाशक को नहीं बुलाया जाएगा।

3

आप ऑब्जेक्ट कैसे बना रहे हैं?

यदि आप वैश्विक चर या स्थैतिक चर का उपयोग कर रहे हैं, तो विनाशक को सामान्य रूप से बाहर निकलने पर विचार किया जाएगा।

उदाहरण के लिए, कार्यक्रम

#include <iostream> 

class Test 
{ 
    const char *msg; 

public: 

    Test(const char *msg) 
    : msg(msg) 
    {} 

    ~Test() 
    { 
     std::cout << "In destructor: " << msg << std::endl; 
    } 
}; 

Test globalTest("GlobalTest"); 

int main(int, char *argv[]) 
{ 
    static Test staticTest("StaticTest"); 

    return 0; 
} 

प्रिंटों बाहर

In destructor: StaticTest 
In destructor: GlobalTest 
2

यह स्पष्ट करने से पहले आवेदन समाप्त हो जाता है वैश्विक स्मृति आवंटन को मुक्त करने के लोकगीत है। मुझे लगता है कि हम में से अधिकांश इसे आदत से बाहर करते हैं और क्योंकि हमें लगता है कि संरचना के बारे में "भूलना" खराब है। सी दुनिया में यह समरूपता का कानून है कि किसी भी आवंटन में कहीं भी एक विलोपन होना चाहिए। यदि वे जानते हैं और अभ्यास करते हैं तो सी ++ प्रोग्रामर अलग-अलग सोचते हैं।

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

मुझे इन दिनों किसी भी आत्म-सम्मानित डेस्कटॉप ऑपरेटिंग सिस्टम के बारे में पता नहीं है जो मेमोरी लीक को किसी एप्लिकेशन के वर्चुअल एड्रेस स्पेस से बाहर निकलने की अनुमति देगा। जब कोई विस्तृत मेमोरी बहीखाता नहीं है तो आपका माइलेज एम्बेडेड डिवाइस पर भिन्न हो सकता है।

+1

यदि आप एप्लिकेशन विकास प्रयास के हिस्से के रूप में पुन: प्रयोज्य कोड लिखते हैं तो यह लोकगीत नहीं है। यदि आप सभी भावी संदर्भों को नहीं जानते हैं जिसमें आप जिस कोड को पुन: उपयोग करने की उम्मीद करते हैं, उसका उपयोग किया जाएगा, तो सावधानी के पक्ष में गलती करना सबसे अच्छा है। मेरी अपनी परियोजनाएं ज्यादातर कोड होती हैं जो मुझे ऐप तर्क के पतले लिबास के साथ पुन: उपयोग करने की उम्मीद करती है। –

+0

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

+0

आप पुस्तकालयों के अंदर पुनः उपयोग करने योग्य कोड के लिए सही हैं। लेकिन अनुप्रयोगों के लिए नहीं। किसी भी आधुनिक ऑपरेटिंग सिस्टम में वैश्विक कोड (यानी पुस्तकालय) के बाहर कोई स्मृति रिसाव नहीं है। ये बस अस्तित्व में नहीं है। एप्लिकेशन समाप्त होने पर पूरी मेमोरी एरिया को मार दिया जाता है। सभी() और malloc() की धूल में बदल जाता है, भले ही मुक्त() या हटाएं()। – Thorsten79

0

सी ++ जैसी भाषाओं में कचरा संग्रह नहीं है, यह समाप्ति से पहले साफ करने का सबसे अच्छा अभ्यास है। आप इसे विनाशक मित्र वर्ग के साथ कर सकते हैं।

class Singleton{ 
... 
    friend class Singleton_Cleanup; 
}; 
class Singleton_Cleanup{ 
public: 
    ~Singleton_Cleanup(){ 
     delete Singleton::ptr; 
    } 
}; 

कार्यक्रम को शुरू करते ही साफ अप कक्षा बनाएं और फिर नाशक सिंगलटन सफाई बुलाया जाएगा बाहर निकलने पर। यह ऑपरेटिंग सिस्टम पर जाने की तुलना में अधिक वर्बोज़ हो सकता है लेकिन यह आरएआईआई सिद्धांतों का पालन करता है और आपके सिंगलटन ऑब्जेक्ट में आवंटित संसाधनों के आधार पर यह आवश्यक हो सकता है।