फ़ाइनलाइज़र
कंप्यूटर विज्ञान में, फाइनलाइज़र या अंतिम विधि एक विशेष विधि (कंप्यूटर प्रोग्रामिंग) है | जो अंतिम रूप देती है | सामान्यतः सफाई का कुछ रूप ऑब्जेक्ट के विनाश के समय फाइनलाइज़र को निष्पादित किया जाता है | ऑब्जेक्ट निर्माण से पहले, और प्रारंभकर्ता का पूरक होता है | जिसे मेमोरी प्रबंधन के बाद ऑब्जेक्ट निर्माण के समय निष्पादित किया जाता है। उचित उपयोग में कठिनाई और उनके द्वारा जोड़ी जाने वाली जटिलता के कारण फ़ाइनलाइज़र को कुछ लोगों द्वारा दृढ़ता से हतोत्साहित किया जाता है, और इसके अतिरिक्त विकल्प सुझाए जाते हैं | मुख्य रूप से डिस्पोजल पैटर्न [1] (समस्याएं देखें) है।
फ़ाइनलाइज़र शब्द का उपयोग अधिकतर ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग में किया जाता है। ऑब्जेक्ट-ओरिएंटेड और कार्यात्मक प्रोग्रामिंग प्रोग्रामिंग भाषा जो कचरा संग्रह (कंप्यूटर साइंस) का उपयोग करती हैं | जिनमें से मूलरूप स्मॉलटाक है। यह विनाशक (कंप्यूटर प्रोग्रामिंग) के विपरीत है | जो नियतात्मक रूप से C++ के नियतात्मक ऑब्जेक्ट जीवनकाल के साथ भाषाओं में अंतिम रूप देने के लिए कहा जाने वाला विधि है।[2][3] ये सामान्यतः अनन्य होते हैं | भाषा में या तो फ़ाइनलाइज़र (यदि स्वचालित रूप से कचरा एकत्र किया जाता है) या विध्वंसक (यदि मैन्युअल रूप से मेमोरी प्रबंधित की जाती है), किन्तु दुर्लभ स्थितियों में भाषा में C++/CLI और D (प्रोग्रामिंग लैंग्वेज) और दोनों हो सकते हैं। संदर्भ गणना का स्थिति (कचरा संग्रह का पता लगाने के अतिरिक्त), शब्दावली अलग होती है। विधि उपयोग में, डिस्ट्रक्टर्स को संदर्भित करने के लिए फाइनलाइज़र का भी उपयोग किया जा सकता है | क्योंकि ये भी अंतिम रूप देते हैं, और कुछ सूक्ष्म भेद तैयार किए जाते हैं | शब्दावली देखें अंतिम शब्द का उपयोग उस वर्ग को इंगित करने के लिए भी किया जाता है | जो वंशानुक्रम (ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग) नहीं हो सकता है | यह असंबंधित है।
क्योंकि ये भी अंतिम रूप देते हैं, और कुछ सूक्ष्म भेद तैयार किए जाते हैं - #शब्दावली देखें। अंतिम शब्द का उपयोग उस वर्ग को इंगित करने के लिए भी किया जाता है जो वंशानुक्रम (ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग) नहीं हो सकता है; यह असंबंधित है।क्योंकि ये भी अंतिम रूप देते हैं, और
शब्दावली
फाइनलाइज़र और फ़ाइनलाइज़ेशन बनाम विध्वंसक और विनाश की शब्दावली लेखकों के बीच अलग होती है और कभी-कभी अस्पष्ट होती है।
सामान्य उपयोग में, विध्वंसक एक विधि है | जिसे नियतात्मक रूप से ऑब्जेक्ट के विनाश पर कहा जाता है, और मूलरूप C++ विध्वंसक है | जबकि फाइनलाइज़र को कचरा कलेक्टर द्वारा गैर-नियतात्मक रूप से कहा जाता है, और मूलरूप जावा (प्रोग्रामिंग भाषा) finalize
को अंतिम रूप देने के तरीके है |
उन भाषाओं के लिए जो संदर्भ गिनती के माध्यम से कचरा संग्रह को प्रयुक्त करती हैं | शब्दावली अलग होती है | कुछ भाषाओं जैसे उद्देश्य C और पर्ल विनाशक का उपयोग करते हुए, और अन्य भाषाओं जैसे कि पायथन फ़ाइनलाइज़र का उपयोग करते हुए (प्रति युक्ति, पायथन कचरा एकत्र किया जाता है, किन्तु संदर्भ C पायथन कार्यान्वयन इसके बाद से संस्करण 2.0 संदर्भ गिनती और कचरा संग्रह के संयोजन का उपयोग करता है)। यह दर्शाता है कि संदर्भ गणना का परिणाम अर्ध-नियतात्मक ऑब्जेक्ट जीवनकाल में होता है | उन ऑब्जेक्ट के लिए जो चक्र का भाग नहीं हैं | ऑब्जेक्ट को निश्चित रूप से नष्ट कर दिया जाता है जब संदर्भ संख्या शून्य हो जाती है, किन्तु चक्र का भाग होने वाली ऑब्जेक्ट को गैर-नियतात्मक रूप से नष्ट कर दिया जाता है। कचरा संग्रह के एक अलग रूप का भाग होता है ।
कुछ संकीर्ण विधि उपयोगों में, कंस्ट्रक्टर और विनाशक भाषा-स्तर के शब्द हैं | जिसका अर्थ है कि वर्ग में परिभाषित विधियाँ, जबकि इनिशियलाइज़र और फ़ाइनलाइज़र कार्यान्वयन-स्तर की शर्तें हैं | जिसका अर्थ है ऑब्जेक्ट निर्माण या विनाश के समय बुलाई जाने वाली विधियाँ है। इस प्रकार उदाहरण के लिए C शार्प (प्रोग्रामिंग भाषा) के लिए मूल विनिर्देश C भाषा विनाशकों को संदर्भित करती है | तथापि C कचरा-एकत्रित है, किन्तु सामान्य भाषा इंफ्रास्ट्रक्चर (सीएलआई) के लिए विनिर्देश, और इसके रनटाइम पर्यावरण के कार्यान्वयन के रूप में सामान्य भाषा रनटाइम (सीएलआर), जिसे फाइनलाइजर्स कहा जाता है। यह C भाषा समिति के नोट्स में परिलक्षित होता है | जो भाग में पढ़ता है | C कंपाइलर डिस्ट्रक्टर्स को संकलित करता है | संभवतः उदाहरण फाइनलाइज़र एस [4][5] यह शब्दावली भ्रमित करने वाली है, और इस प्रकार C स्पेक के अधिक हाल के संस्करण भाषा-स्तरीय पद्धति को फ़ाइनलाइज़र के रूप में संदर्भित करते हैं।[6]
एक अन्य भाषा जो d इस शब्दावली भेद को नहीं बनाती है | चूँकि d कक्षाएं कचरा एकत्र की जाती हैं | उनके सफाई कार्यों को विध्वंसक कहा जाता है।[7]
प्रयोग
फाइनलाइजेशन का उपयोग अधिकतर सफाई के लिए, मेमोरी या अन्य संसाधनों को जारी करने के लिए किया जाता है | मैनुअल मेमोरी प्रबंधन के माध्यम से आवंटित मेमोरी को हटाने के लिए; यदि संदर्भ गणना का उपयोग किया जाता है तो संदर्भों को स्पष्ट करने के लिए (संदर्भ संख्या में कमी) संसाधनों को जारी करने के लिए, विशेष रूप से संसाधन अधिग्रहण प्रारंभिक (आरएआईआई) मुहावरे में है या किसी ऑब्जेक्ट को अपंजीकृत करने के लिए अंतिम रूप देने की मात्रा भाषाओं के बीच महत्वपूर्ण रूप से अलग होती है | C++ में व्यापक अंतिमीकरण से, जिसमें मैनुअल स्मृति प्रबंधन, संदर्भ गणना, और नियतात्मक ऑब्जेक्ट जीवन काल होता है | जावा में अधिकाशतः कोई अंतिम रूप नहीं दिया जाता है, जिसमें गैर-नियतात्मक ऑब्जेक्ट जीवनकाल होता है और अधिकाशतः ट्रेसिंग कचरा संग्राहक के साथ प्रयुक्त किया जाता है। यह भी संभव है कि कम या कोई स्पष्ट (उपयोगकर्ता-निर्दिष्ट) अंतिम रूप न हो, किन्तु संकलक, दुभाषिया, या रनटाइम द्वारा निष्पादित महत्वपूर्ण अंतर्निहित अंतिमकरण के स्थिति में यह सामान्य है | जैसा कि पायथन के सीपीथॉन संदर्भ कार्यान्वयन में, या ऐप्पल के ऑब्जेक्टिव-C के कार्यान्वयन में स्वचालित संदर्भ गणना में, जो दोनों अंतिम रूप से संदर्भों को स्वचालित रूप से तोड़ देते हैं। फाइनलाइज़र में मनमाना कोड सम्मिलित हो सकता है | विशेष रूप से जटिल उपयोग ऑब्जेक्ट को ऑब्जेक्ट पूल में स्वचालित रूप से वापस करना है।
फाइनलाइजेशन के समय मेमोरी डीलोकेशन C++ जैसी भाषाओं में सामान्य है | जहां मैनुअल मेमोरी मैनेजमेंट मानक है, किन्तु प्रबंधित भाषाओं में भी होता है | जब मेमोरी को प्रबंधित हीप के बाहर आवंटित किया गया है |(बाह्य रूप से भाषा के लिए) जावा में यह जावा मूल इंटरफ़ेस (जेएनआई) और के साथ होता है | ByteBuffer
नॉन-ब्लॉकिंग I/O (जावा) में ऑब्जेक्ट नया I/O (एनआईओ) यह उत्तरार्द्ध कचरा संग्रहकर्ता के इन बाहरी संसाधनों को ट्रैक करने में असमर्थ होने के कारण समस्याएँ उत्पन्न कर सकता है | इसलिए उन्हें आक्रामक रूप से पर्याप्त रूप से एकत्र नहीं किया जाएगा, और अप्रबंधित मेमोरी को समाप्त करने के कारण आउट-ऑफ़-मेमोरी त्रुटियाँ उत्पन्न कर सकता है | देशी मेमोरी का इलाज करके इससे बचा जा सकता है | संसाधन के रूप में और डिस्पोजल पैटर्न का उपयोग करते हुए, जैसा कि नीचे चर्चा की गई है।
फ़ाइनलाइज़र सामान्यतः बहुत कम आवश्यक होते हैं और विध्वंसक की तुलना में बहुत कम उपयोग किए जाते हैं। वे बहुत कम आवश्यक हैं क्योंकि कचरा संग्रह स्मृति प्रबंधन को स्वचालित करता है, और बहुत कम उपयोग किया जाता है | क्योंकि वे सामान्यतः निश्चित रूप से निष्पादित नहीं होते हैं | उन्हें समय पर सही से या बिल्कुल भी नहीं बुलाया जा सकता है, और निष्पादन वातावरण की पूर्वानुमान नहीं की जा सकती है और इस प्रकार कोई भी क्लीनअप जो निश्चित रूप से किया जाना चाहिए | इसके अतिरिक्त किसी अन्य विधि द्वारा किया जाना चाहिए | अधिकाशतः मैन्युअल रूप से निपटान पैटर्न के माध्यम से विशेष रूप से, जावा और पायथन दोनों इस बात की गारंटी नहीं देते हैं कि फाइनलाइजर्स को कभी भी बुलाया जाएगा, और इस प्रकार उन्हें सफाई के लिए विश्वास नहीं किया जा सकता है।
उनके निष्पादन पर प्रोग्रामर नियंत्रण की कमी के कारण, सामान्यतः किसी भी किन्तु सबसे सामान्य संचालन के लिए फाइनलाइज़र से बचने की पक्षसमर्थन की जाती है। विशेष रूप से, विध्वंसक में अधिकाशतः किए जाने वाले संचालन सामान्यतः अंतिम रूप देने वालों के लिए उपयुक्त नहीं होते हैं। सामान्य विरोधी प्रतिमान फाइनलाइज़र लिखना है जैसे कि वे विध्वंसक थे | जो अनावश्यक और अप्रभावी दोनों हैं | अंतिम रूप देने वालों और विध्वंसकों के बीच अंतर के कारण यह C++ प्रोग्रामर के बीच विशेष रूप से सामान्य है | क्योंकि रिसोर्स एक्विजिशन इज़ इनिशियलाइज़ेशन (आरएआईआई) मुहावरे के बाद मुहावरेदार C ++ में डिस्ट्रक्टर्स का भारी उपयोग किया जाता है।
वाक्य-विन्यास
फाइनलाइज़र का उपयोग करने जावास्क्रिप्ट (प्रोग्रामिंग भाषा) में C++/CLI, C तेज़ (प्रोग्रामिंग लैंग्वेज) C, क्लीन (प्रोग्रामिंग भाषा) , जावा (प्रोग्रामिंग भाषा) , जावा (प्रोग्रामिंग लैंग्वेज), जावास्क्रिप्ट (प्रोग्रामिंग लैंग्वेज) और पायथन (प्रोग्रामिंग लैंग्वेज) सम्मिलित हैं। वाक्य-विन्यास भाषा के अनुसार अधिक अलग होता है।
जावा में, फाइनलाइज़र विधि है जिसे finalize
कहा जाता है | जो ओवरराइड Object.finalize
विधि करता है।[8]
जावास्क्रिप्ट में, finalizationRegistry आपको किसी ऑब्जेक्ट के कूड़ा-कचरा एकत्र करने पर कॉलबैक का अनुरोध करने की अनुमति देता है।
पायथन में, फाइनलाइज़र विधि है जिसे __del__
. कहा जाता है |
पर्ल में, फ़ाइनलाइज़र विधि है | जिसे DESTROY
. कहा जाता है |
C में, अंतिमकर्ता (मानक के पुराने संस्करणों में विनाशक कहा जाता है) एक विधि है जिसका नाम ~
पूर्वसर्ग, के रूप में वर्ग का नाम है | जैसा कि ~Foo
में है | यह C++ विनाशक के समान सिंटैक्स है, और इन विधियों को मूल रूप से डिस्ट्रक्टर्स कहा जाता था, अलग-अलग व्यवहार होने के अतिरिक्त, C++ के साथ सादृश्य द्वारा, किन्तु इसके कारण होने वाले भ्रम के कारण इसका नाम बदलकर फाइनल कर दिया गया।[6]
C++/सीएलआई में, जिसमें विनाशक और फाइनलाइज़र दोनों हैं | विनाशक एक विधि है जिसका नाम ~
पूर्वसर्ग, के रूप में वर्ग का नाम है | जैसा कि ~Foo
(C # में), और फाइनलाइज़र एक विधि है जिसका नाम !
वर्ग का नाम है | जैसा कि पूर्वसर्ग, के रूप में !Foo
. है |
फाइनलाइजर्स को मानक पुस्तकालय में रनटाइम.runtime.SetFinalizer
फ़ंक्शन को कॉल करके एकल सूचक पर लागू किया जाता है।[9]
कार्यान्वयन
फाइनलाइज़र को तब कहा जाता है | जब ऑब्जेक्ट (कंप्यूटर विज्ञान) कचरा एकत्र किया जाता है | ऑब्जेक्ट कचरा (पहुंच योग्य) बनने के बाद, किन्तु इससे पहले कि उसकी मेमोरी को हटा दिया जाए। कचरा संग्राहक के विवेक पर अंतिम रूप से गैर-नियतात्मक रूप से होता है, और कभी नहीं हो सकता है। यह विनाशकों के साथ विरोधाभासी है | जिन्हें नियतात्मक रूप से कहा जाता है | जैसे ही कोई ऑब्जेक्ट अब उपयोग में नहीं होती है, और अनियंत्रित कार्यक्रम समाप्ति के स्थिति को छोड़कर सदैव कहा जाता है। ऑब्जेक्ट-विशिष्ट संचालन करने की आवश्यकता के कारण फ़ाइनलाइज़र अधिकाशतः उदाहरण विधियाँ हैं।
कचरा संग्राहक को ऑब्जेक्ट के पुनरुत्थान की संभावना का भी ध्यान रखना चाहिए। सामान्यतः यह पहले फाइनलाइजर्स को निष्पादित करके किया जाता है | फिर जांच की जाती है कि क्या कोई ऑब्जेक्ट फिर से जीवित हो गई है, और यदि ऐसा है, तो उनके विनाश को रद्द कर दिया गया है। यह अतिरिक्त जांच संभावित रूप से महंगी है | साधारण कार्यान्वयन सभी कचरे की फिर से जाँच करता है | यदि एक भी ऑब्जेक्ट को अंतिम रूप दिया जाता है और इस तरह दोनों धीमा हो जाता है और कचरा संग्रह को जटिल बना देता है। इस कारण से, फ़ाइनलाइज़र वाली ऑब्जेक्ट को फ़ाइनलाइज़र के बिना ऑब्जेक्ट की तुलना में कम बार एकत्र किया जा सकता है |(केवल कुछ चक्रों पर), संसाधन लीक जैसे शीघ्र अंतिमकरण पर निर्भर होने के कारण होने वाली समस्याओं को बढ़ा देता है।
यदि किसी ऑब्जेक्ट को पुनर्जीवित किया जाता है, तो आगे का प्रश्न है कि क्या इसके फाइनलाइज़र को फिर से नष्ट कर दिया जाता है | जब इसे नष्ट कर दिया जाता है | विनाशकों के विपरीत, फाइनलाइज़र को संभावित रूप से कई बार बुलाया जाता है। यदि अंतिम रूप देने वालों को पुनर्जीवित ऑब्जेक्ट के लिए बुलाया जाता है, तो वस्तुएं बार-बार खुद को पुनर्जीवित कर सकती हैं और अविनाशी हो सकती हैं | यह पायथन 3.4 से पहले पायथन के C पायथन कार्यान्वयन में और C # जैसी सीएलआर भाषाओं में होता है। इससे बचने के लिए, जावा, ऑब्जेक्टिव-C (कम से कम हाल के ऐप्पल कार्यान्वयन में), और पायथन 3.4 से पायथन सहित कई भाषाओं में, ऑब्जेक्ट को एक बार में अंतिम रूप दिया जाता है | जिसके लिए ट्रैकिंग की आवश्यकता होती है | यदि ऑब्जेक्ट को अभी तक अंतिम रूप दिया गया है।
अन्य स्थितियों में, विशेष रूप से सीएलआर भाषाओं जैसे C #, अंतिम रूप से ऑब्जेक्ट से अलग से ट्रैक किया जाता है, और ऑब्जेक्ट को अंतिम रूप देने के लिए बार-बार पंजीकृत या अपंजीकृत किया जा सकता है।
समस्याएं
कार्यान्वयन के आधार पर, अंतिमकर्ता बड़ी संख्या में समस्याएं उत्पन्न कर सकते हैं, और इस प्रकार कई अधिकारियों द्वारा दृढ़ता से हतोत्साहित किया जाता है।[10][11] इन समस्याओं में सम्मिलित हैं:[10]* फाइनलाइजर्स को समय पर या बिल्कुल भी नहीं बुलाया जा सकता है, इसलिए उन पर राज्य को जारी रखने, दुर्लभ संसाधनों को जारी करने, या कुछ और महत्वपूर्ण करने के लिए विश्वास नहीं किया जा सकता है।
- फ़ाइनलाइज़र का परिणाम ऑब्जेक्ट पुनरुत्थान हो सकता है, जो अधिकाशतः प्रोग्रामिंग त्रुटि होती है और जिसकी बहुत संभावना अधिक धीमी हो जाती है और कचरा संग्रहण को जटिल बना देती है।
- फाइनलाइज़र कचरा संग्रह के आधार पर चलाए जाते हैं, जो सामान्यतः प्रबंधित मेमोरी दबाव पर आधारित होते हैं - वे अन्य संसाधनों की कमी के स्थिति में नहीं चलते हैं, और इस प्रकार अन्य दुर्लभ संसाधनों के प्रबंधन के लिए उपयुक्त नहीं होते हैं।
- फ़ाइनलाइज़र निर्दिष्ट क्रम में नहीं चलते हैं, और वर्ग अपरिवर्तनीय ्स पर विश्वास नहीं कर सकते हैं (क्योंकि वे अन्य ऑब्जेक्ट्स को संदर्भित कर सकते हैं जिन्हें पहले ही अंतिम रूप दिया जा चुका है)।
- धीमे फाइनलाइज़र अन्य फ़ाइनलाइज़र में देरी कर सकते हैं।
- फ़ाइनलाइज़र के अपवादों को सामान्यतः नियंत्रित नहीं किया जा सकता है, क्योंकि फ़ाइनलाइज़र अनिर्दिष्ट वातावरण में चलाया जाता है, और इसे या तो अनदेखा किया जा सकता है या अनियंत्रित प्रोग्राम समाप्ति का कारण बन सकता है।
- फ़ाइनलाइज़र प्रोग्राम इनवेरिएंट्स का उल्लंघन करते हुए लाइव ऑब्जेक्ट्स को संदर्भित और गलती से अंतिम रूप दे सकते हैं।
- फाइनलाइज़र सिंक्रनाइज़ेशन मुद्दों का कारण बन सकता है, यहां तक कि अनुक्रमिक (एकल-थ्रेडेड) कार्यक्रमों में भी, जब एक अलग धागे में अंतिम रूप दिया जाता है।[12]
- फ़ाइनलाइज़र डेडलॉक का कारण बन सकता है यदि सिंक्रोनाइज़ेशन मैकेनिज़्म जैसे ताले का उपयोग किया जाता है, निर्दिष्ट क्रम में नहीं चलने और संभवतः समवर्ती रूप से चलने के कारण।
- प्रोग्राम समाप्ति के समय चलाए जाने वाले फ़ाइनलाइज़र सामान्य रनटाइम वातावरण पर विश्वास नहीं कर सकते हैं, और इस प्रकार गलत धारणाओं के कारण विफल हो सकते हैं - इस कारण फ़ाइनलाइज़र अधिकाशतः समाप्ति के समय नहीं चलते हैं।
इसके अलावा, प्रोग्रामिंग त्रुटियों के कारण या अप्रत्याशित रीचैबिलिटी के कारण कचरा होने की उम्मीद से परे पहुंच योग्य ऑब्जेक्ट के कारण अंतिम रूप से चलने में विफल हो सकते हैं। उदाहरण के लिए, जब पायथन अपवाद को पकड़ता है (या अपवाद इंटरएक्टिव मोड में नहीं पकड़ा जाता है), यह स्टैक फ्रेम का संदर्भ रखता है जहां अपवाद उठाया गया था, जो उस स्टैक फ्रेम से संदर्भित ऑब्जेक्ट को जीवित रखता है।
जावा में, सुपरक्लास में फ़ाइनलाइज़र उपवर्ग में कचरा संग्रह को धीमा कर सकता है, क्योंकि फ़ाइनलाइज़र संभावित रूप से उपवर्ग में फ़ील्ड्स को संदर्भित कर सकता है, और इस प्रकार फ़ाइनलाइज़र के चलने के बाद, अगले चक्र तक फ़ील्ड को कचरा एकत्र नहीं किया जा सकता है।[10]वंशानुक्रम पर रचना का उपयोग करके इससे बचा जा सकता है।
संसाधन प्रबंधन
संसाधनों को जारी करने के लिए फ़ाइनलाइज़र का उपयोग करने के लिए सामान्य एंटी-पैटर्न है, C ++ के रिसोर्स एक्विजिशन इज़ इनिशियलाइज़ेशन (आरएआईआई) मुहावरे के अनुरूप: इनिशियलाइज़र (कन्स्ट्रक्टर) में संसाधन प्राप्त करें, और इसे फ़ाइनलाइज़र (विनाशक) में रिलीज़ करें। यह कई कारणों से काम नहीं करता है। मूल रूप से, अंतिम रूप देने वालों को कभी नहीं बुलाया जा सकता है, और यहां तक कि अगर बुलाया जाता है, तो उन्हें समय पर सही से नहीं बुलाया जा सकता है - इस प्रकार संसाधनों को जारी करने के लिए अंतिम रूप देने वालों का उपयोग सामान्यतः संसाधन रिसाव का कारण होगा। इसके अलावा, फाइनलाइजर्स को निर्धारित क्रम में नहीं बुलाया जाता है, जबकि संसाधनों को अधिकाशतः विशिष्ट क्रम में जारी करने की आवश्यकता होती है, अधिकाशतः विपरीत क्रम जिसमें वे प्राप्त किए गए थे। इसके अलावा, जैसा कि अंतिम रूप से कचरा संग्रहकर्ता के विवेक पर कहा जाता है, उन्हें अधिकाशतः संसाधन दबाव के अतिरिक्त प्रबंधित स्मृति दबाव (जब थोड़ी प्रबंधित स्मृति उपलब्ध होती है) के तहत बुलाया जाएगा - यदि दुर्लभ संसाधन कचरा द्वारा आयोजित किए जाते हैं किन्तु वहां बहुत कुछ है उपलब्ध प्रबंधित स्मृति की, कचरा संग्रह नहीं हो सकता है, इस प्रकार इन संसाधनों को पुनः प्राप्त नहीं किया जा सकता है।
इस प्रकार स्वचालित संसाधन प्रबंधन के लिए फाइनलाइजर्स का उपयोग करने के अतिरिक्त, कचरा-एकत्रित भाषाओं में संसाधनों को मैन्युअल रूप से प्रबंधित करना चाहिए, सामान्यतः निपटान पैटर्न का उपयोग करके। इस स्थिति में संसाधनों को अभी भी इनिशियलाइज़र में अधिग्रहित किया जा सकता है, जिसे स्पष्ट रूप से ऑब्जेक्ट इंस्टेंटेशन पर कहा जाता है, किन्तु निपटान विधि में जारी किया जाता है। निपटान विधि को स्पष्ट रूप से, या स्पष्ट रूप से C # के जैसे भाषा निर्माणों द्वारा कहा जा सकता है using
, मई आपको try
-साथ-संसाधन, या पायथन with
.
हालाँकि, कुछ स्थितियों में संसाधनों को जारी करने के लिए डिस्पोजल पैटर्न और फ़ाइनलाइज़र दोनों का उपयोग किया जाता है। यह अधिकतर सीएलआर भाषाओं में पाया जाता है जैसे C #, जहां निपटान के लिए बैकअप के रूप में अंतिमकरण का उपयोग किया जाता है: जब संसाधन का अधिग्रहण किया जाता है, तो प्राप्त करने वाली ऑब्जेक्ट को अंतिम रूप देने के लिए कतारबद्ध किया जाता है ताकि संसाधन ऑब्जेक्ट विनाश पर जारी हो, तथापि संसाधन न हो मैनुअल निपटान द्वारा जारी किया गया।
नियतात्मक और गैर-नियतात्मक ऑब्जेक्ट जीवनकाल
नियतात्मक ऑब्जेक्ट जीवनकाल वाली भाषाओं में, विशेष रूप से C++, संसाधन प्रबंधन अधिकाशतः संसाधन कब्जे के जीवनकाल को ऑब्जेक्ट जीवनकाल से बांधकर किया जाता है, आरंभीकरण के समय संसाधनों को प्राप्त करना और अंतिम रूप देने के समय उन्हें जारी करना; इसे रिसोर्स एक्विजिशन इज़ इनिशियलाइज़ेशन (आरएआईआई) के रूप में जाना जाता है। यह सुनिश्चित करता है कि संसाधन कब्ज़ा वर्ग अपरिवर्तनीय है, और जब ऑब्जेक्ट नष्ट हो जाती है तो संसाधनों को तत्काल जारी किया जाता है।
हालाँकि, गैर-नियतात्मक ऑब्जेक्ट जीवनकाल वाली भाषाओं में - जिसमें कचरा संग्रह वाली सभी प्रमुख भाषाएँ सम्मिलित हैं, जैसे C#, जावा, और पायथन - यह काम नहीं करती है, क्योंकि अंतिम रूप समय पर नहीं हो सकता है या बिल्कुल भी नहीं हो सकता है, और इस प्रकार संसाधन संसाधन रिसाव के कारण लंबे समय तक या बिल्कुल भी जारी नहीं किया जा सकता है। इन भाषाओं में संसाधनों को सामान्यतः निपटान पैटर्न के माध्यम से मैन्युअल रूप से प्रबंधित किया जाता है: संसाधन अभी भी प्रारंभ के समय प्राप्त किए जा सकते हैं, किन्तु कॉल करके जारी किए जाते हैं dispose
विधि। फिर भी, इन भाषाओं में संसाधनों को जारी करने के लिए अंतिम रूप देना सामान्य विरोधी पैटर्न है, और कॉल करना भूल जाता है dispose
अभी भी संसाधन रिसाव का कारण बनेगा।
कुछ स्थितियों में दोनों तकनीकों को स्पष्ट निपटान पद्धति का उपयोग करके संयुक्त किया जाता है, किन्तु बैकअप के रूप में अंतिम रूप देने के समय किसी भी स्थिर संसाधनों को भी जारी किया जाता है। यह सामान्यतः C # में पाया जाता है, और जब भी किसी संसाधन को प्राप्त किया जाता है, और जब भी संसाधन जारी किया जाता है, तो अंतिम रूप देने के लिए अंतिम रूप देने के लिए ऑब्जेक्ट को पंजीकृत करके कार्यान्वित किया जाता है।
ऑब्जेक्ट पुनरुत्थान
यदि उपयोगकर्ता द्वारा निर्दिष्ट फ़ाइनलाइज़र की अनुमति दी जाती है, तो अंतिमकरण के लिए ऑब्जेक्ट पुनरुत्थान का कारण संभव है, क्योंकि फ़ाइनलाइज़र मनमाना कोड चला सकते हैं, जो जीवित ऑब्जेक्ट से नष्ट होने वाली ऑब्जेक्ट के संदर्भ बना सकते हैं। कचरा संग्रह के बिना भाषाओं के लिए, यह गंभीर बग है, और झूलने वाले संदर्भों और स्मृति सुरक्षा उल्लंघनों का कारण बनता है; कचरा संग्रह वाली भाषाओं के लिए, इसे कचरा संग्रहकर्ता द्वारा रोका जाता है, सामान्यतः कचरा संग्रह में एक और कदम जोड़कर (सभी उपयोगकर्ता-निर्दिष्ट फ़ाइनलाइज़र चलाने के बाद, पुनरुत्थान की जाँच करें), जो कचरा संग्रह को जटिल और धीमा कर देता है।
इसके अलावा, ऑब्जेक्ट पुनरुत्थान का अर्थ है कि ऑब्जेक्ट को नष्ट नहीं किया जा सकता है, और पैथोलॉजिकल स्थितियों में ऑब्जेक्ट सदैव अंतिम रूप देने के समय खुद को पुनर्जीवित कर सकती है, खुद को अविनाशी बना सकती है। इसे रोकने के लिए, कुछ भाषाएँ, जैसे जावा और पायथन (पायथन 3.4 से) केवल एक बार ऑब्जेक्ट को अंतिम रूप देती हैं, और पुनर्जीवित ऑब्जेक्ट को अंतिम रूप नहीं देती हैं। ऑब्जेक्ट-दर-ऑब्जेक्ट के आधार पर किसी ऑब्जेक्ट को अंतिम रूप दिया गया है या नहीं, यह ट्रैक करके ठोस रूप से किया जाता है। उद्देश्य-C भी अंतिम रूप से ट्रैक करता है (कम से कम हाल ही में एप्पल संस्करण) समान कारणों से, पुनरुत्थान को बग के रूप में मानना।
.NET फ्रेमवर्क में एक अलग दृष्टिकोण का उपयोग किया जाता है, विशेष रूप से C# और विजुअल बेसिक .NET, जहां अंतिम रूप को ऑब्जेक्ट के अतिरिक्त क्यू द्वारा ट्रैक किया जाता है। इस स्थिति में, यदि उपयोगकर्ता द्वारा निर्दिष्ट फाइनलाइज़र प्रदान किया जाता है, तो डिफ़ॉल्ट रूप से ऑब्जेक्ट को केवल एक बार अंतिम रूप दिया जाता है (यह निर्माण पर अंतिम रूप देने के लिए कतारबद्ध होता है, और इसे अंतिम रूप देने के बाद हटा दिया जाता है), किन्तु इसे कॉल करके बदला जा सकता है GC
मापांक। कॉल करके अंतिम रूप से रोका जा सकता है GC.SuppressFinalize
, जो ऑब्जेक्ट को डीक्यू करता है, या कॉल करके पुनः सक्रिय करता है GC.ReRegisterForFinalize
, जो ऑब्जेक्ट को कतारबद्ध करता है। इनका विशेष रूप से उपयोग किया जाता है जब संसाधन प्रबंधन के लिए अंतिम रूप देने के लिए निपटान पैटर्न के पूरक के रूप में उपयोग किया जाता है, या ऑब्जेक्ट पूल को प्रयुक्त करते समय।
इनिशियलाइज़ेशन के साथ कंट्रास्ट
अंतिम रूप देना औपचारिक रूप से आरंभीकरण (प्रोग्रामिंग) का पूरक है - आरंभीकरण जीवनकाल की शुरुआत में होता है, अंत में अंतिम रूप - किन्तु व्यवहार में महत्वपूर्ण रूप से अलग होता है। चर और ऑब्जेक्ट दोनों को आरंभीकृत किया जाता है, अधिकतर मान निर्दिष्ट करने के लिए, किन्तु सामान्य तौर पर केवल ऑब्जेक्ट को अंतिम रूप दिया जाता है, और सामान्य तौर पर मूल्यों को स्पष्ट करने की कोई आवश्यकता नहीं होती है - मेमोरी को केवल ऑपरेटिंग सिस्टम द्वारा हटाया और पुनः प्राप्त किया जा सकता है।
आरंभिक मान निर्दिष्ट करने के अलावा, इनिशियलाइज़ेशन का उपयोग अधिकतर संसाधनों को प्राप्त करने या किसी सेवा (जैसे आयोजन प्रबंधकर्ता) के साथ किसी ऑब्जेक्ट को पंजीकृत करने के लिए किया जाता है। इन कार्रवाइयों में सममित रिलीज या अपंजीकृत क्रियाएं होती हैं, और इन्हें फाइनलाइज़र में सममित रूप से संभाला जा सकता है, जो आरएआईआई में किया जाता है।चूँकि, कई भाषाओं में, विशेष रूप से कचरा संग्रहण वाली भाषाओं में, ऑब्जेक्ट का जीवनकाल असममित है: ऑब्जेक्ट निर्माण निश्चित रूप से कोड में कुछ स्पष्ट बिंदु पर होता है, किन्तु ऑब्जेक्ट विनाश गैर-नियतात्मक रूप से, कुछ अनिर्दिष्ट वातावरण में, कचरा संग्राहक के विवेक पर होता है। इस विषमता का अर्थ है कि अंतिम रूप को आरंभीकरण के पूरक के रूप में प्रभावी रूप से उपयोग नहीं किया जा सकता है, क्योंकि यह समयबद्ध तरीके से, निर्दिष्ट क्रम में, या निर्दिष्ट वातावरण में नहीं होता है। स्पष्ट बिंदु पर ऑब्जेक्ट का निपटान करके समरूपता को आंशिक रूप से बहाल किया जाता है, किन्तु इस स्थिति में निपटान और विनाश एक ही बिंदु पर नहीं होता है, और एक ऑब्जेक्ट एक निपटान में हो सकती है किन्तु अभी भी जीवित अवस्था में हो सकती है, जो वर्ग आक्रमणकारियों को कमजोर करती है और उपयोग को जटिल बनाता है।
वेरिएबल्स को सामान्यतः उनके जीवनकाल की शुरुआत में आरंभ किया जाता है, किन्तु उनके जीवनकाल के अंत में अंतिम रूप नहीं दिया जाता है -चूँकि यदि चर के पास इसके मूल्य के रूप में ऑब्जेक्ट है, तो ऑब्जेक्ट को अंतिम रूप दिया जा सकता है। कुछ स्थितियों में वेरिएबल्स को भी अंतिम रूप दिया जाता है: जीसीसी एक्सटेंशन वेरिएबल्स को अंतिम रूप देने की अनुमति देते हैं।
के साथ संबंध finally
जैसा कि नामकरण, अंतिम रूप और में परिलक्षित होता है finally
निर्माण दोनों समान उद्देश्यों को पूरा करते हैं: कुछ अंतिम क्रिया करना, सामान्यतः कुछ और समाप्त होने के बाद सफाई करना। जब वे घटित होते हैं तो उनमें अंतर होता है - a finally
खंड निष्पादित किया जाता है जब प्रोग्राम निष्पादन संबंधित के शरीर को छोड़ देता है try
खंड - यह स्टैक के खुलने के समय होता है, और इस प्रकार लंबित ढेर होता है finally
खंड, क्रम में - जबकि अंतिमकरण तब होता है जब कोई ऑब्जेक्ट नष्ट हो जाती है, जो स्मृति प्रबंधन पद्धति के आधार पर होती है, और सामान्य तौर पर अंतिम रूप देने की प्रतीक्षा में ऑब्जेक्ट का सेट होता है - अधिकाशतः ढेर पर - जो किसी विशिष्ट क्रम में होने की आवश्यकता नहीं होती है।
हालाँकि, कुछ स्थितियों में ये मेल खाते हैं। C++ में, ऑब्जेक्ट विनाश नियतात्मक है, और व्यवहार a finally
किसी ऑब्जेक्ट के साथ उसके मूल्य के रूप में स्थानीय चर होने से क्लॉज का उत्पादन किया जा सकता है, जिसका दायरा ब्लॉक के शरीर से मेल खाता है try
खंड - ऑब्जेक्ट को अंतिम रूप दिया जाता है (नष्ट) जब निष्पादन इस दायरे से बाहर निकलता है, ठीक उसी तरह जैसे कि कोई था finally
खंड। इस कारण से, C++ में a नहीं है finally
निर्माण - अंतर यह है कि अंतिमकरण को कॉल साइट के अतिरिक्त विध्वंसक विधि के रूप में वर्ग परिभाषा में परिभाषित किया गया है finally
खंड।
इसके विपरीत, ए के स्थिति में finally
कोरटाइन में खंड, पायथन जनरेटर की तरह, कोरटाइन कभी भी समाप्त नहीं हो सकता है - केवल कभी उपज - और इस प्रकार सामान्य निष्पादन में finally
खंड कभी निष्पादित नहीं होता है। यदि कोई कोरटाइन के उदाहरणों को ऑब्जेक्ट के रूप में व्याख्या करता है, तो finally
क्लॉज को ऑब्जेक्ट का फाइनलाइज़र माना जा सकता है, और इस प्रकार इसे तब निष्पादित किया जा सकता है जब इंस्टेंस कचरा एकत्र किया जाता है। पायथन शब्दावली में, कोरटाइन की परिभाषा जनरेटर फ़ंक्शन है, जबकि इसका उदाहरण जनरेटर इटरेटर है, और इस प्रकार ए finally
जेनरेटर फ़ंक्शन में खंड इस फ़ंक्शन से तत्काल जेनरेटर इटरेटर्स में अंतिम रूप बन जाता है।
इतिहास
ऑब्जेक्ट विनाश की तारीखों में एक अलग कदम के रूप में अंतिम रूप देने की धारणा Montgomery (1994),[13] ऑब्जेक्ट कंस्ट्रक्शन में इनिशियलाइज़ेशन के पहले के अंतर के अनुरूप Martin & Odell (1992).[14] इस बिंदु से पहले का साहित्य इस प्रक्रिया के लिए विनाश का उपयोग करता है, अंतिम रूप देने और डीललोकेशन को अलग नहीं करता है, और इस अवधि से जुड़ी प्रोग्रामिंग भाषाएं, जैसे C++ और पर्ल, विनाश शब्द का उपयोग करती हैं। प्रभावशाली पुस्तक डिजाइन पैटर्न्स (1994) में अंतिम रूप देने और अंतिम रूप देने की शर्तों का भी उपयोग किया जाता है।[lower-alpha 1][15] 1995 में जावा की शुरूआत निहित थी finalize
विधियाँ, जिन्होंने इस शब्द को लोकप्रिय बनाया और इसे कचरा संग्रह से जोड़ा, और इस बिंदु से भाषाएँ सामान्यतः इस अंतर को बनाती हैं और विशेष रूप से कचरा संग्रह के संदर्भ में शब्द को अंतिम रूप देती हैं।
यह भी देखें
- कचरा संग्रह (कंप्यूटर विज्ञान), विशेष रूप से कचरा संग्रह (कंप्यूटर विज्ञान) #निर्धारणवाद पर अनुभाग
- ऑब्जेक्ट जीवनकाल
- इनिशियलाइज़ेशन (प्रोग्रामिंग) प्रक्रिया और संबंधित इनिशियलाइज़र पैटर्न
टिप्पणियाँ
- ↑ Published 1994, with a 1995 copyright.
संदर्भ
- ↑ Jagger, Perry & Sestoft 2007, p. 542, "In C++, a destructor is called in a determinate manner, whereas, in C#, a finalizer is not. To get determinate behavior from C#, one should use
Dispose.
- ↑ Boehm, Hans-J. (2002). विध्वंसक, अंतिम रूप देने वाले और तुल्यकालन. Symposium on Principles of Programming Languages (POPL).
- ↑ Jagger, Perry & Sestoft 2007, p. 542, C++ destructors versus C# finalizers C++ destructors are determinate in the sense that they are run at known points in time, in a known order, and from a known thread. They are thus semantically very different from C# finalizers, which are run at unknown points in time, in an unknown order, from an unknown thread, and at the discretion of the garbage collector.
- ↑ In full: "We're going to use the term "destructor" for the member which executes when an instance is reclaimed. Classes can have destructors; structs can't. Unlike in C++, a destructor cannot be called explicitly. Destruction is non-deterministic – you can't reliably know when the destructor will execute, except to say that it executes at some point after all references to the object have been released. The destructors in an inheritance chain are called in order, from most descendant to least descendant. There is no need (and no way) for the derived class to explicitly call the base destructor. The C# compiler compiles destructors to the appropriate CLR representation. For this version that probably means an instance finalizer that is distinguished in metadata. CLR may provide static finalizers in the future; we do not see any barrier to C# using static finalizers.", May 12th, 1999.
- ↑ What’s the difference between a destructor and a finalizer?, Eric Lippert, Eric Lippert’s Blog: Fabulous Adventures In Coding, 21 Jan 2010
- ↑ 6.0 6.1 Jagger, Perry & Sestoft 2007, p. 542, "In the previous version of this standard, what is now referred to as a “finalizer” was called a “destructor”. Experience has shown that the term “destructor” caused confusion and often resulted in incorrect expectations, especially to programmers knowing C++. In C++, a destructor is called in a determinate manner, whereas, in C#, a finalizer is not. To get determinate behavior from C#, one should use
Dispose.
" - ↑ Class destructors Class destructors in D
- ↑ java.lang, क्लास ऑब्जेक्ट: finalize() finalize
- ↑ "Runtime package - runtime - PKG.go.dev".
- ↑ 10.0 10.1 10.2 "MET12-J. Do not use finalizers", Dhruv Mohindra, The CERT Oracle Secure Coding Standard for Java, 05. Methods (MET) Archived 2014-05-04 at the Wayback Machine
- ↑ object.__del__(self), The Python Language Reference, 3. Data model: "...
__del__()
methods should do the absolute minimum needed to maintain external invariants." - ↑ Hans-J. Boehm, Finalization, Threads, and the Java™ Technology-Based Memory Model, JavaOne Conference, 2005.
- ↑ Montgomery 1994, p. 120, "As with object instantiation, design for object termination can benefit from implementation of two operations for each class—a finalize and a terminate operation. A finalize operation breaks associations with other objects, ensuring data structure integrity."
- ↑ Montgomery 1994, p. 119, "Consider implementing class instantiation as a create and initialize operation, as suggested by Martin and Odell. The first allocates storage for new objects, and the second constructs the object to adhere to specifications and constraints."
- ↑ "Every new class has a fixed implementation overhead (initialization, finalization, etc.).", "destructor In C++, an operation that is automatically invoked to finalize an object that is about to be deleted."
अग्रिम पठन
- Jagger, Jon; Perry, Nigel; Sestoft, Peter (2007). Annotated C# Standard. Morgan Kaufmann. ISBN 978-0-12-372511-0.
- Martin, James; Odell, James J. (1992). Object-oriented analysis and design. Prentice-Hall. ISBN 978-0-13-630245-2.
- Montgomery, Stephen (January 24, 1994). Object-Oriented Information Engineering: Analysis, Design, and Implementation. Academic Press. ISBN 978-0-12-505040-1.
बाहरी संबंध
- "Finalize Instead Of Proper Destructor", WikiWikiWeb – comparison of जावा फ़ाइनलाइज़र with C++ destructors
- Paul Krill, "Oracle recommends axing जावा object finalizer", JavaWorld Mar 29, 2017.