ओवरराइडिंग ऑब्जेक्ट है। फ़िनाइल () वास्तव में खराब है?


34

ओवरराइडिंग के खिलाफ मुख्य दो तर्क हैं Object.finalize():

  1. आपको यह तय करने के लिए नहीं मिलता है कि इसे कब बुलाया जाए।

  2. यह बिल्कुल नहीं कहा जा सकता है।

अगर मैं इसे सही ढंग से समझता हूं, तो मुझे नहीं लगता कि वे Object.finalize()इतने नफरत करने के लिए पर्याप्त कारण हैं ।

  1. यह वीएम कार्यान्वयन और जीसी पर निर्भर करता है कि किसी ऑब्जेक्ट को डील करने के लिए सही समय कब निर्धारित किया जाए, न कि डेवलपर। जब Object.finalize()बुलाया जाता है तो यह तय करना महत्वपूर्ण क्यों है ?

  2. आम तौर पर, और मुझे सही करें अगर मैं गलत हूं, तो केवल उस समय Object.finalize()कॉल नहीं किया जाएगा जब जीसी को चलाने का मौका मिलने से पहले आवेदन समाप्त हो गया हो। हालाँकि, जब भी आवेदन की प्रक्रिया इसके साथ समाप्त हो जाती है, तो वस्तु को वैसे ही समाप्त कर दिया जाता है। इसलिए Object.finalize()बुलाया नहीं गया क्योंकि इसे बुलाने की जरूरत नहीं थी। डेवलपर क्यों करेगा देखभाल?

जब भी मैं उन वस्तुओं का उपयोग कर रहा हूं, जिन्हें मुझे मैन्युअल रूप से बंद करना है (जैसे फ़ाइल हैंडल और कनेक्शन), तो मुझे बहुत निराशा होती है। अगर किसी वस्तु का कार्यान्वयन होता है close(), तो मुझे लगातार जाँच करनी होगी , और मुझे यकीन है कि मैंने अतीत में कुछ बिंदुओं पर कुछ कॉलों को याद किया है। इसे close()लागू करने से इन वस्तुओं का निपटान करने के लिए केवल वीएम और जीसी पर छोड़ देना अधिक सरल और सुरक्षित क्यों नहीं है Object.finalize()?


1
यह भी ध्यान दें: जावा 1.0 युग के कई एपीआई की तरह, थ्रेड शब्दार्थ भी finalize()थोड़ा गड़बड़ है। यदि आप कभी भी इसे लागू करते हैं, तो सुनिश्चित करें कि यह एक ही ऑब्जेक्ट पर अन्य सभी तरीकों के संबंध में थ्रेड-सुरक्षित है।
बिलसी।

2
जब आप लोगों को यह कहते हुए सुनते हैं कि अंतिम रूप खराब हैं, तो उनका मतलब यह नहीं है कि यदि आपके पास है तो आपका कार्यक्रम काम करना बंद कर देगा; उनका मतलब है कि अंतिम रूप देने का पूरा विचार बहुत बेकार है।
user253751

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

अपने अंतिम पैराग्राफ को संबोधित करते हुए, आप अपनी ओर से बहुत कम प्रयास के साथ फ़ाइल हैंडल और कनेक्शन जैसी बंद चीजों को संभालने के लिए इसे जावा पर छोड़ सकते हैं। कोशिश-के साथ संसाधनों के ब्लॉक का उपयोग करें - यह पहले से ही उत्तर और टिप्पणियों में कुछ अन्य बार उल्लेख किया गया है, लेकिन मुझे लगता है कि यह यहां डालने लायक है। इसके लिए Oracle ट्यूटोरियल docs.oracle.com/javase/tutorial/essential/exception/…
Jeutnarg

जवाबों:


45

मेरे अनुभव में, ओवरराइडिंग का एक और केवल एक कारण है Object.finalize(), लेकिन यह एक बहुत अच्छा कारण है :

finalize()यदि आप कभी भी इनवॉइस करना भूल जाते हैं, तो त्रुटि लॉगिंग कोड को सूचित करें close()

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

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

इसलिए, यह योजना है जिसे मैं अनिवार्य निपटान कहता हूं , और यह निर्धारित करता है कि प्रोग्रामर हमेशा स्पष्ट रूप से सब कुछ बंद करने Closeableया लागू करने के लिए जिम्मेदार है AutoCloseable। (कोशिश के साथ संसाधनों का बयान अभी भी स्पष्ट समापन के रूप में गिना जाता है।) बेशक, प्रोग्रामर भूल सकता है, इसलिए कि जहां अंतिम रूप से खेलने में आता है, लेकिन एक जादुई परी के रूप में नहीं जो जादुई चीजों को अंत में सही कर देगा: यदि अंतिम रूप से पता चलता है कि close()लागू नहीं किया गया था, यह करता है नहींइसे लागू करने का प्रयास, ठीक है क्योंकि वहाँ (गणितीय निश्चितता के साथ) n00b प्रोग्रामर की भीड़ होगी जो इस काम पर भरोसा करेंगे कि वे बहुत आलसी थे या बहुत अनुपस्थित थे। इसलिए, अनिवार्य निपटान के साथ, जब अंतिम रूप से पता चलता है कि close()आह्वान नहीं किया गया था, तो यह एक उज्ज्वल लाल त्रुटि संदेश में प्रवेश करता है, प्रोग्रामर को अपने s-- er, उसके सामान को ठीक करने के लिए बड़े वसा वाले सभी बड़े अक्षरों के साथ बताता है।

एक अतिरिक्त लाभ के रूप में, अफवाह यह है कि "जेवीएम एक तुच्छ अंतिम रूप () विधि को अनदेखा करेगा (जैसे कि जो कुछ भी किए बिना वापस आ जाता है, जैसे कि ऑब्जेक्ट क्लास में परिभाषित किया गया है)", इसलिए अनिवार्य निपटान के साथ आप सभी अंतिम रूप से बच सकते हैं अपने पूरे सिस्टम में भूमि के ऊपर ( Alip का जवाब देखने के अपने कोडिंग से कैसे भयानक इस भूमि के ऊपर है पर जानकारी के लिए) finalize()इस तरह विधि:

@Override
protected void finalize() throws Throwable
{
    if( Global.DEBUG && !closed )
    {
        Log.Error( "FORGOT TO CLOSE THIS!" );
    }
    //super.finalize(); see alip's comment on why this should not be invoked.
}

इसके पीछे विचार यह है कि Global.DEBUGएक static finalचर जिसका मूल्य संकलन समय पर जाना जाता है, इसलिए यदि यह है falseतो संकलक पूरे ifबयान के लिए किसी भी कोड का उत्सर्जन नहीं करेगा , जो इसे एक तुच्छ (खाली) अंतिम रूप देगा, जो बदले में इसका मतलब है कि आपकी कक्षा को ऐसा माना जाएगा जैसे कि उसका कोई अंतिम रूप नहीं है। (सी # में यह एक अच्छा #if DEBUGब्लॉक के साथ किया जाएगा , लेकिन हम क्या कर सकते हैं, यह जावा है, जहां हम मस्तिष्क में अतिरिक्त उपरि के साथ कोड में स्पष्ट सादगी का भुगतान करते हैं।)

अनिवार्य निपटान के बारे में अधिक, डॉट नेट में संसाधनों के निपटान के बारे में अतिरिक्त चर्चा के साथ, यहाँ: michael.gr: अनिवार्य निपटान बनाम "निपटान-निपटान" घृणा


2
@MikeNakis मत भूलना, क्लोज़ेबल को दूसरी बार कहे जाने पर कुछ नहीं करने के रूप में परिभाषित किया गया है: docs.oracle.com/javase/7/docs/api/java/io/Closeable.html । मैं मानता हूं कि मैंने कभी-कभी एक चेतावनी लॉग की है जब मेरी कक्षाएं दो बार बंद हो जाती हैं, लेकिन तकनीकी रूप से आप ऐसा करने वाले नहीं हैं। हालांकि तकनीकी रूप से, .close () को एक बार से अधिक क्लोजेबल पर कॉल करना पूरी तरह से मान्य है।
पैट्रिक एम

1
@ यह सब उबलता है कि क्या आपको अपने परीक्षण पर भरोसा है या आपको अपने परीक्षण पर भरोसा नहीं है। यदि आपको अपने परीक्षण पर भरोसा नहीं है, तो निश्चित रूप से, आगे बढ़ें और अंतिम स्थिति को भी भुगतना होगा close(), बस मामले में। मेरा मानना ​​है कि अगर मेरे परीक्षण पर भरोसा नहीं किया जाना है, तो मैं बेहतर उत्पादन के लिए प्रणाली को जारी नहीं करता हूं।
माइक निकीस जूल

3
@ माइक, if( Global.DEBUG && ...निर्माण के लिए काम करने के लिए इसलिए JVM finalize()तुच्छ के रूप में विधि की उपेक्षा करेगा , Global.DEBUGसंकलन समय पर निर्धारित किया जाना चाहिए (इंजेक्शन के विपरीत आदि) तो क्या मृत कोड होगा। super.finalize()अगर JVM को गैर-तुच्छ (मान की परवाह किए बिना Global.DEBUG, कम से कम हॉटस्पॉट 1.8 पर) इलाज के लिए इफ़ ब्लॉक के बाहर कॉल भी पर्याप्त है , भले ही सुपर क्लास की #finalize()तुच्छ हो!
अलाप

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

1
अक्सर जो अनदेखी की जाती है, वह वस्तुओं के पहले-से-अपेक्षित संग्रह का जोखिम है जो फाइनल में संसाधनों को बहुत खतरनाक बनाता है। जावा 9 से पहले, यह सुनिश्चित करने का एकमात्र तरीका है कि कोई फ़ाइनलीज़र संसाधन को बंद नहीं करता है, जबकि यह अभी भी उपयोग में है, ऑब्जेक्ट पर सिंक्रनाइज़ करने के लिए है, फ़ाइनलीज़र और विधि (ओं) का उपयोग करते हुए। इसलिए इसमें काम आता है java.io। यदि इस तरह की थ्रेड सुरक्षा इच्छा सूची में नहीं थी, तो यह ओवरहेड से प्रेरित होकर जोड़ता है finalize()...
Holger

28

जब भी मैं उन वस्तुओं का उपयोग कर रहा हूं, जिन्हें मुझे मैन्युअल रूप से बंद करना है (जैसे फ़ाइल हैंडल और कनेक्शन), तो मुझे बहुत निराशा होती है। [...] इसे close()लागू करने से इन वस्तुओं का निपटान करने के लिए सिर्फ वीएम और जीसी पर छोड़ देना अधिक सरल और सुरक्षित क्यों नहीं है Object.finalize()?

क्योंकि फ़ाइल हैंडल और कनेक्शन (अर्थात, Linux और POSIX सिस्टम पर फ़ाइल डिस्क्रिप्टर ) काफी दुर्लभ संसाधन हैं (आप कुछ सिस्टमों पर उनमें से 256 तक सीमित हो सकते हैं, या कुछ अन्य पर 16384 तक देख सकते हैं; सेटरलिमिट देखें (2) ) इस बात की कोई गारंटी नहीं है कि ऐसे सीमित संसाधनों को समाप्त करने से बचने के लिए जीसी को अक्सर (या सही समय पर) पर्याप्त कहा जाएगा। और अगर जीसी को पर्याप्त नहीं कहा जाता है (या अंतिम समय पर सही तरीके से नहीं चलाया जाता है) तो आप उस (संभवतः कम) सीमा तक पहुंच जाएंगे।

JVM में अंतिम रूप देना एक "सर्वश्रेष्ठ प्रयास" है। इसे कॉल नहीं किया जा सकता है, या इसे काफी देर से बुलाया जा सकता है ... विशेष रूप से, यदि आपके पास बहुत अधिक रैम है या यदि आपका प्रोग्राम बहुत सारी वस्तुओं को आवंटित नहीं करता है (या यदि उनमें से ज्यादातर किसी पुराने से आगे बढ़ने से पहले मर जाते हैं। एक पीढ़ी के पीढ़ीगत जीसी द्वारा), जीसी को शायद ही कभी कहा जा सकता है, और अंतिम रूप बहुत बार नहीं चल सकते हैं (या यहां तक ​​कि बिल्कुल भी नहीं चल सकते हैं)।

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


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

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

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

2
"यदि आप [फाइल डिस्क्रिप्टर] लीक करने से डरते हैं, तो अंतिम उपाय का उपयोग अतिरिक्त उपाय के रूप में करें, मुख्य के रूप में नहीं।" यह कथन मुझे अजीब लगता है। यदि आप अपना कोड अच्छी तरह से डिज़ाइन करते हैं, तो क्या आपको वास्तव में निरर्थक कोड पेश करना चाहिए जो कई स्थानों पर सफाई फैलाता है?
मुलहो

2
@BasileStarynkevitch आपकी बात यह है कि एक आदर्श दुनिया में, हाँ, अतिरेक बुरा है, लेकिन व्यवहार में, जहाँ आप सभी प्रासंगिक पहलुओं को नहीं भूल सकते हैं, बेहतर है कि खेद से सुरक्षित हो?
मुस्तहो जूल 6'15

13

मामले को इस तरह से देखें: आपको केवल वह कोड लिखना चाहिए जो (a) सही हो (अन्यथा आपका प्रोग्राम सादा गलत है) और (b) आवश्यक (अन्यथा आपका कोड बहुत बड़ा है, जिसका अर्थ है कि अधिक RAM आवश्यक है, अधिक चक्र खर्च किए गए बेकार चीजें, इसे समझने के लिए अधिक प्रयास, इसे बनाए रखने के लिए अधिक समय आदि आदि।

अब विचार करें कि यह क्या है जो आप एक फाइनल में करना चाहते हैं। या तो यह आवश्यक है। उस स्थिति में आप इसे अंतिम रूप नहीं दे सकते, क्योंकि आप नहीं जानते कि यह कहा जाएगा। यह पर्याप्त अच्छा नहीं है। या यह आवश्यक नहीं है - तब आपको इसे पहली जगह में नहीं लिखना चाहिए! किसी भी तरह से, इसे अंतिम रूप में रखना गलत विकल्प है।

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


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

अगर मेरे पास RAM हैवी, महंगी-से-बनाने योग्य, क्लोज करने योग्य ऑब्जेक्ट है और मैं इसे कमजोर रूप से संदर्भित करने का निर्णय लेता हूं, ताकि जरूरत न होने पर इसे क्लियर किया जा सके, तो मैं finalize()इसे बंद करने के लिए उपयोग कर सकता हूं, अगर gc साइकिल को वास्तव में खाली करने की आवश्यकता होती है राम। अन्यथा, मैं ऑब्जेक्ट को रैम में रखने और इसे हर बार उपयोग करने की आवश्यकता के बजाय इसे बंद करने के लिए रखूंगा। निश्चित रूप से, जब भी यह संसाधन खोला जाता है, तब तक इसे मुक्त नहीं किया जाएगा, जब तक कि यह वस्तु प्राप्त न हो जाए, लेकिन मुझे यह सुनिश्चित करने की आवश्यकता नहीं है कि मेरे संसाधनों को एक निश्चित समय में मुक्त किया जाए।
Kröw

8

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

इसके अतिरिक्त, ट्राई-विथ-रिसोर्स का उपयोग करना आसान बनाने के लिए 'क्लोजेबल' ऑब्जेक्ट्स को बंद कर देता है। यदि आप इस निर्माण से परिचित नहीं हैं, तो मेरा सुझाव है कि आप इसे देखें : https://docs.oracle.com/javase/tutorial/essential/exception/tryResourceClose.html


8

संसाधनों को जारी करने के लिए इसे अंतिम रूप देने के लिए छोड़ने के अलावा आम तौर पर एक बुरा विचार है, अंतिम रूप देने योग्य वस्तुएं ओवरहेड प्रदर्शन के साथ आती हैं।

से जावा सिद्धांत और व्यवहार: कचरा संग्रहण और प्रदर्शन (ब्रायन गोएज़), finalizers अपने दोस्त नहीं हैं :

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


बहुत बढ़िया बिंदु। मेरा उत्तर देखें जो प्रदर्शन के ऊपरी भाग से बचने का साधन प्रदान करता है finalize()
माइक नाकिस

7

बचने के लिए मेरा (कम से कम) पसंदीदा कारण Object.finalizeयह नहीं है कि वस्तुएं आपकी उम्मीद के बाद अंतिम रूप दे सकती हैं, बल्कि इससे पहले कि आप इसकी उम्मीद कर सकें, वे अंतिम रूप दे सकते हैं । समस्या यह नहीं है कि एक वस्तु जो अभी भी दायरे में है, इसे दायरे से बाहर करने से पहले अंतिम रूप दिया जा सकता है यदि जावा यह तय करता है कि यह अब उपलब्ध नहीं है।

void test() {
   HasFinalize myObject = ...;
   OutputStream os = myObject.stream;

   // myObject is no-longer reachable at this point, 
   // even though it is in scope. But objects are finalized
   // based on reachability.
   // And since finalization is on another thread, it 
   // could happen before or in the middle of the write .. 
   // closing the stream and causing much fun.
   os.write("Hello World");
}

देखें इस सवाल का अधिक जानकारी के लिए। इससे भी अधिक मजेदार यह है कि यह निर्णय केवल हॉट-स्पॉट ऑप्टिमाइजेशन किक के बाद किया जा सकता है, जिससे यह डिबग के लिए दर्दनाक हो सकता है।


1
बात यह है कि HasFinalize.streamअपने आप में एक अलग अंतिम वस्तु होनी चाहिए। यही है, अंतिम रूप को अंतिम रूप HasFinalizeनहीं देना चाहिए या सफाई करने का प्रयास नहीं करना चाहिए stream। या अगर यह होना चाहिए, तो इसे streamदुर्गम बनाना चाहिए ।
तेज़


4

मुझे लगातार जाँच करनी होती है कि क्या किसी वस्तु में क्लोज़ () का कार्यान्वयन है, और मुझे यकीन है कि मैंने अतीत में कुछ बिंदुओं पर इसमें कुछ कॉल मिस कर दी हैं।

ग्रहण में, मुझे एक चेतावनी मिलती है जब भी मैं कुछ ऐसी चीज़ों को बंद करना भूल जाता हूं जो लागू होते हैं Closeable/ AutoCloseable। मुझे यकीन नहीं है कि यह एक ग्रहण चीज है या यदि यह आधिकारिक संकलक का हिस्सा है, लेकिन आप वहां आपकी मदद करने के लिए इसी तरह के स्थिर विश्लेषण उपकरणों का उपयोग कर सकते हैं। उदाहरण के लिए, FindBugs शायद आपको यह जांचने में मदद कर सकते हैं कि क्या आप किसी संसाधन को बंद करना भूल गए हैं।


1
अच्छे विचार का उल्लेख है AutoCloseable। यह कोशिश-के-संसाधनों के साथ संसाधनों का प्रबंधन करने के लिए मस्तिष्क-मृत-आसान बनाता है। यह प्रश्न में कई तर्कों को स्पष्ट करता है।

2

आपके पहले प्रश्न के लिए:

यह वीएम कार्यान्वयन और जीसी पर निर्भर करता है कि किसी ऑब्जेक्ट को डील करने के लिए सही समय कब निर्धारित किया जाए, न कि डेवलपर। जब Object.finalize()बुलाया जाता है तो यह तय करना महत्वपूर्ण क्यों है ?

खैर, जेवीएम यह निर्धारित करेगा, जब किसी वस्तु के लिए आवंटित किए गए भंडारण को पुनः प्राप्त करना एक अच्छा बिंदु है। यह जरूरी नहीं है कि वह समय जब संसाधन साफ ​​हो, आप प्रदर्शन करना चाहते हैं finalize(), ऐसा होना चाहिए। यह सचित्र है एसओ पर प्रश्न "अंतिम रूप () जावा 8 में जोरदार पहुंच योग्य वस्तु पर बुलाया गया" है । वहां, एक close()विधि द्वारा एक finalize()विधि को बुलाया गया है , जबकि एक ही वस्तु द्वारा धारा से पढ़ने का प्रयास अभी भी लंबित है। तो अच्छी तरह से ज्ञात संभावना के अलावा finalize()जिसे देर से आने का रास्ता कहा जाता है, संभावना है कि इसे बहुत जल्दी कहा जाता है।

आपके दूसरे प्रश्न का आधार:

आम तौर पर, और सही होने पर मुझे सही, केवल समय Object.finalize() कॉल नहीं किया जाएगा जब जीसी को चलाने का मौका मिलने से पहले आवेदन समाप्त हो गया हो।

बस गलत है। अंतिम रूप से समर्थन करने के लिए जेवीएम की कोई आवश्यकता नहीं है। ठीक है, यह पूरी तरह से गलत नहीं है क्योंकि आप अभी भी इसकी व्याख्या कर सकते हैं क्योंकि "आवेदन अंतिम रूप देने से पहले ही समाप्त हो गया था", यह मानते हुए कि आपका आवेदन कभी भी समाप्त हो जाएगा।

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

यह बिंदु भी यही कारण है कि अंतिम रूप से समर्थन के साथ JVM पर भी, संसाधन सफाई के लिए इस पर निर्भर होना खतरनाक है। कचरा संग्रह स्मृति प्रबंधन का हिस्सा है और इसलिए यह स्मृति की जरूरतों से शुरू होता है। यह संभव है कि कचरा संग्रह कभी नहीं चलता क्योंकि पूरे रनटाइम के दौरान पर्याप्त मेमोरी होती है (ठीक है, जो अभी भी "जीसी को चलाने का मौका मिलने से पहले" समाप्त हो गया है "विवरण में फिट बैठता है, किसी तरह)। यह भी संभव है कि जीसी चलता है लेकिन बाद में, पर्याप्त मेमोरी पुनः प्राप्त होती है, इसलिए अंतिम कतार संसाधित नहीं होती है।

दूसरे शब्दों में, देशी संसाधनों का प्रबंधन इस तरह से अभी भी स्मृति प्रबंधन के लिए एक विदेशी है। हालांकि यह गारंटी दी जाती है कि OutOfMemoryErrorस्मृति मुक्त करने के लिए पर्याप्त प्रयासों के बाद ही इसे फेंका जाता है, जो मूल संसाधनों और अंतिमकरण पर लागू नहीं होता है। यह संभव है कि किसी फ़ाइल को खोलना अपर्याप्त संसाधनों के कारण विफल हो जाए, जबकि अंतिम रूप से कतार उन वस्तुओं से भरी होती है, जो इन संसाधनों को मुक्त कर सकती हैं, यदि अंतिम रूप से कभी भाग गया हो ...

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