आप कभी भी अंतिम रूप क्यों लागू करेंगे ()?


371

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

मुझे सीएस में स्कूल नहीं दिया गया था, लेकिन मैं जावा में पेशेवर रूप से अब एक दशक के करीब प्रोग्रामिंग कर रहा हूं और मैंने कभी किसी को finalize()उत्पादन प्रणाली में कभी भी लागू नहीं देखा । इसका मतलब यह नहीं है कि इसके उपयोग नहीं हैं, या जिन लोगों के साथ मैंने काम किया है वे इसे सही कर रहे हैं।

तो मेरा प्रश्न यह है finalize()कि लागू करने के लिए ऐसे कौन से मामले हैं, जिन्हें भाषा के भीतर किसी अन्य प्रक्रिया या वाक्य रचना के माध्यम से अधिक मज़बूती से नियंत्रित नहीं किया जा सकता है?

कृपया विशिष्ट परिदृश्य या अपना अनुभव प्रदान करें, बस एक जावा पाठ पुस्तक को दोहराएं, या अंतिम उपयोग के लिए पर्याप्त नहीं है, जैसा कि इस प्रश्न का इरादा नहीं है।


HI अंतिम रूप दें () विधि बहुत अच्छी तरह से यहाँ बताई गई
समीर काज़ी

2
अधिकांश एप्लिकेशन और लाइब्रेरी कोड कभी उपयोग नहीं करेंगे finalize()। हालाँकि, प्लेटफ़ॉर्म लाइब्रेरी कोड , जैसे कि SocketInputStream, कॉल करने वाले की ओर से देशी संसाधनों का प्रबंधन करता है, ऐसा रिसोर्स लीक के जोखिम को कम करने की कोशिश करता है (या समतुल्य तंत्रों का उपयोग करता है, जैसे PhantomReferenceकि बाद में जोड़े गए।) इसलिए पारिस्थितिकी तंत्र को उनकी आवश्यकता है। भले ही 99.9999% डेवलपर्स कभी नहीं लिखेंगे।
ब्रायन गोएट्ज़

जवाबों:


231

आप इसे बाहरी संसाधन (सॉकेट, फ़ाइल, आदि) को रखने वाली वस्तु के लिए एक बैकस्टॉप के रूप में उपयोग कर सकते हैं। एक close()विधि और दस्तावेज़ को लागू करें जिसे इसे कहा जाना चाहिए।

यदि आप यह नहीं कर पाए हैं तो प्रोसेसिंग finalize()करने के लिए कार्यान्वयन करें close()। हो सकता है कि किसी चीज़ के साथ डंप किया stderrगया हो, जिसे आप एक छोटी गाड़ी वाले के बाद साफ कर रहे हों।

यह एक असाधारण / छोटी गाड़ी की स्थिति में अतिरिक्त सुरक्षा प्रदान करता है। हर कॉलर try {} finally {}हर बार सही सामान नहीं करने वाला है । दुर्भाग्यपूर्ण, लेकिन अधिकांश वातावरण में सच है।

मैं मानता हूं कि इसकी जरूरत शायद ही हो। और जैसा कि टिप्पणीकार बताते हैं, यह जीसी ओवरहेड के साथ आता है। लंबे समय तक चलने वाले ऐप में "बेल्ट और सस्पेंडर्स" सुरक्षा की आवश्यकता होने पर ही उपयोग करें।

मुझे लगता है कि जावा 9 के रूप में, Object.finalize()पदावनत किया जाता है! वे हमें java.lang.ref.Cleanerऔर java.lang.ref.PhantomReferenceविकल्प के रूप में इंगित करते हैं ।


44
बस यह सुनिश्चित करें कि एक अपवाद को अंतिम रूप से कभी नहीं फेंका जाए (), या कचरा संग्रहकर्ता उस वस्तु की सफाई जारी नहीं रखेगा, और आपको एक स्मृति रिसाव मिलेगा।
स्कफमैन

17
अंतिम रूप से बुलाया जाने की गारंटी नहीं है, इसलिए संसाधन जारी करने पर इसकी गणना न करें।
Flicken

19
skaffman - मुझे विश्वास नहीं है कि (कुछ छोटी गाड़ी JVM कार्यान्वयन से अलग)। Object.finalize () javadoc से: यदि कोई अनकहा अपवाद अंतिम विधि द्वारा फेंका जाता है, तो अपवाद को अनदेखा कर दिया जाता है और उस ऑब्जेक्ट को अंतिम रूप दिया जाता है।
जॉन एम

4
आपका प्रस्ताव लंबे समय तक लोगों के कीड़े (नज़दीकी कॉलिंग नहीं) छिपा सकता है। मैं ऐसा करने की सलाह नहीं दूंगा।
16

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

174

finalize()जेवीएम के लिए एक संकेत है कि आपके कोड को अनिर्दिष्ट समय में निष्पादित करना अच्छा हो सकता है। यह अच्छा है जब आप चाहते हैं कि कोड रहस्यमय ढंग से चलाने में विफल हो।

फाइनल में कुछ भी महत्वपूर्ण नहीं है (मूल रूप से लॉगिंग को छोड़कर कुछ भी) तीन स्थितियों में भी अच्छा है:

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

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

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

अस्वीकरण: मैंने अतीत में जेवीएम कार्यान्वयन पर काम किया है। मुझे फाइनल से नफरत है।


76
अति व्यंग्य न्याय के लिए अपवित्र।
धारणा

32
यह प्रश्न का उत्तर नहीं देता है; यह finalize()बिना किसी कारण के सभी कमियां बताती है कि कोई व्यक्ति वास्तव में इसका उपयोग करना चाहेगा।
मेकैनिकल घोंघा

1
@supercat: प्रेत संदर्भ (उस मामले के लिए सभी संदर्भ) जावा 2 में पेश किए गए थे
स्टीव जेसप

1
@supercat: माफ करना, हाँ "संदर्भ" से मेरा मतलब है java.lang.ref.Referenceऔर इसके उपवर्ग। Java 1 में वैरिएबल :-) था और हां, इसमें फाइनल भी थे।
स्टीव जेसप

2
@SteveJessop: यदि एक बेस-क्लास कंस्ट्रक्टर अन्य संस्थाओं को निर्माण के तहत वस्तु की ओर से अपने राज्य को बदलने के लिए कहता है (एक बहुत ही सामान्य पैटर्न), लेकिन एक व्युत्पन्न वर्ग फ़ील्ड इनिलाइज़र एक अपवाद को फेंक देता है, आंशिक रूप से निर्मित ऑब्जेक्ट को साफ नहीं करना चाहिए खुद के बाद (यानी उन बाहरी संस्थाओं को सूचित करें जिनकी सेवाओं की अब आवश्यकता नहीं है), लेकिन न तो जावा और न ही .NET कोई भी सम-दूरस्थ-स्वच्छ पैटर्न प्रदान नहीं करता है जिसके माध्यम से ऐसा हो सकता है। वास्तव में, वे सफाई कोड तक पहुंचने के लिए सफाई की आवश्यकता वाली चीज़ के संदर्भ के लिए इसे कठिन बनाने के लिए अपने रास्ते से बाहर जाने लगते हैं।
सुपरकैट

58

एक साधारण नियम: कभी भी फाइनल का उपयोग न करें।

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

ब्रायन गोएत्ज़ के एक लेख से:

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


46

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


35

मैं 1998 से जावा पेशेवर कर रहा हूं, और मैंने कभी लागू नहीं किया है finalize()। एक बार भी नहीं।


फिर मैं सार्वजनिक वर्ग की वस्तु को कैसे नष्ट करूं? यह ADF में समस्या पैदा कर रहा है। मूल रूप से यह पृष्ठ को फिर से लोड करने के लिए
माना जाता है

2
@ शिशुप्रधान 'अरविंद' को अंतिम रूप देने से वस्तु नहीं हटती। यह एक तरीका है जिसे आप लागू करते हैं कि जेवीएम कॉल कर सकता है कि क्या और कब कचरा आपकी वस्तु को इकट्ठा करता है।
पॉल टॉम्बलिन

@PaTTomblin, उस विस्तार के लिए ओह धन्यवाद। ADF पर एक पृष्ठ को ताज़ा करने का कोई सुझाव?
शिशुप्रो। अरविंद '

@ इन्फेंटप्रो अरविंद 'कोई विचार नहीं, कभी भी एडीएफ का इस्तेमाल नहीं किया।
पॉल टॉम्बलिन

28

स्वीकृत उत्तर अच्छा है, मैं बस यह जोड़ना चाहता था कि अब वास्तव में इसका उपयोग किए बिना अंतिम रूप देने की कार्यक्षमता है।

"संदर्भ" कक्षाएं देखें। कमजोर संदर्भ, प्रेत संदर्भ और नरम संदर्भ।

आप उन्हें अपनी सभी वस्तुओं का संदर्भ रखने के लिए उपयोग कर सकते हैं, लेकिन यह संदर्भ ALONE GC को नहीं रोकेगा। इसके बारे में साफ-सुथरी बात यह है कि आप इसे हटाए जाने पर एक विधि कह सकते हैं, और इस विधि की गारंटी दी जा सकती है कॉल करने की दी जा सकती है।

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

public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}

यह संकेत है कि किसी को नहीं पता था कि वे क्या कर रहे थे। इस तरह "सफाई" वास्तव में कभी जरूरत नहीं है। जब वर्ग GC'd है, तो यह स्वचालित रूप से किया जाता है।

यदि आपको अंतिम रूप में ऐसा कोड मिलता है तो यह गारंटी है कि इसे लिखने वाला व्यक्ति भ्रमित था।

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

इसका उपयोग कभी भी "क्विकर" चीजों को साफ करने के लिए नहीं किया जाना चाहिए।


3
मेरा मानना ​​है कि जिन वस्तुओं को मुक्त किया जा रहा है, उन पर नज़र रखने के लिए प्रेत संदर्भ एक बेहतर तरीका है।
बिल माइकेल

2
मैंने कभी सुना है "कमजोर संदर्भ" का सबसे अच्छा विवरण प्रदान करने के लिए upvoting।
sscarduzio

मुझे खेद है कि मुझे इसे पढ़ने में इतने साल लग गए, लेकिन यह वास्तव में उत्तरों के लिए एक अच्छा जोड़ है।
स्पेंसर कोरमोस

27

मुझे यकीन नहीं है कि आप इससे क्या बना सकते हैं, लेकिन ...

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

इसलिए मुझे लगता है कि सूर्य को कुछ मामले मिले हैं, जहां उन्हें लगता है कि इसका इस्तेमाल किया जाना चाहिए।


12
मुझे लगता है कि यह "विल डेवलपर हमेशा सही होगा" का भी एक सवाल है?
9

13
लेकिन उन उपयोगों में से कितने उपयोग कर रहे हैं या finalizeवास्तव में इसका उपयोग करने के बजाय समर्थन का परीक्षण कर रहे हैं?
मैकेनिकल घोंघा

मैं विंडोज का उपयोग करता हूं। आप विंडोज में एक ही काम कैसे करेंगे?
गपरानी

2
@damryfbfnetsi: पावती (स्थापित करने का प्रयास beyondgrep.com के माध्यम से) chocolatey.org/packages/ack । या फ़ाइलों में एक सरल खोज का उपयोग करें $FAVORITE_IDE
ब्रायन क्लाइन

21
class MyObject {
    Test main;

    public MyObject(Test t) {    
        main = t; 
    }

    protected void finalize() {
        main.ref = this; // let instance become reachable again
        System.out.println("This is finalize"); //test finalize run only once
    }
}

class Test {
    MyObject ref;

    public static void main(String[] args) {
        Test test = new Test();
        test.ref = new MyObject(test);
        test.ref = null; //MyObject become unreachable,finalize will be invoked
        System.gc(); 
        if (test.ref != null) System.out.println("MyObject still alive!");  
    }
}

====================================

परिणाम:

This is finalize

MyObject still alive!

=====================================

तो आप अंतिम विधि में पहुंच से बाहर पहुंच सकने योग्य उदाहरण बना सकते हैं।


21
किसी कारण से, यह कोड मुझे ज़ोंबी फिल्मों के बारे में सोचता है। आप अपनी वस्तु जीसी और फिर यह फिर से खड़ा है ...
स्टीवेहा

ऊपर अच्छा कोड है। मैं सोच रहा था कि कैसे वस्तु को फिर से अभी-अभी दोबारा पहुंचाया जाए।
lwpro2

15
नहीं, ऊपर बुरा कोड है। यह एक उदाहरण है कि अंतिम रूप खराब क्यों है।
टोनी

याद रखें कि आक्रमण System.gc();करना इस बात की गारंटी नहीं है कि कचरा संग्रहकर्ता वास्तव में चलेगा। यह जीसी का पूरा विवेक है सफाई करने के लिए (शायद अभी भी पर्याप्त मुक्त ढेर के आसपास, शायद ज्यादा खंडित नहीं है, ...)। तो यह प्रोग्रामर द्वारा केवल एक विनम्र अनुरोध है "कृपया, क्या आप मुझे सुन सकते हैं और भाग सकते हैं?" और जैसा कि मैं कहता हूं, "अब चलाओ मत!" भाषाई शब्दों का उपयोग करने के लिए क्षमा करें, लेकिन यह ठीक यही कहता है कि जेवीएम की जीसी कैसे काम करती है।
रोलैंड

10

finalize()संसाधन लीक को पकड़ने के लिए उपयोगी हो सकता है। यदि संसाधन बंद होना चाहिए, लेकिन यह तथ्य नहीं लिख रहा है कि यह लॉग फ़ाइल में बंद नहीं था और इसे बंद कर दें। इस तरह आप संसाधन रिसाव को हटा देते हैं और अपने आप को यह जानने का एक तरीका देते हैं कि यह हो गया है इसलिए आप इसे ठीक कर सकते हैं।

मैं 1.0 अल्फा 3 (1995) के बाद से जावा में प्रोग्रामिंग कर रहा हूं और मुझे अभी तक किसी भी चीज के लिए अंतिम रूप से ओवरराइड नहीं करना है ...


6

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


5

उपरोक्त उत्तरों में एक बिंदु को उजागर करने के लिए: फाइनल जीसी थ्रेड को जीसी थ्रेड पर निष्पादित किया जाएगा। मैंने एक प्रमुख सन डेमो के बारे में सुना है जहां डेवलपर्स ने कुछ फाइनलर्स को एक छोटी नींद दी और जानबूझकर अपने घुटनों पर एक अन्यथा फैंसी 3 डी डेमो लाया।

टेस्ट-एनवी डायग्नोस्टिक्स के संभावित अपवाद के साथ बचने के लिए सबसे अच्छा है।

जावा में एकेल की सोच इस पर एक अच्छा खंड है।


4

हम्म, मैंने एक बार इसका उपयोग उन वस्तुओं को साफ करने के लिए किया था जो किसी मौजूदा पूल में नहीं लौट रहे थे।

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


4

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

यह एक JDK 1.5 के साथ था जो अभी भी व्यापक उपयोग में है।

हमें पता नहीं चलेगा कि कुछ देर बाद तक कुछ गलत हुआ था, लेकिन अंत में अपराधी हमेशा जेएनआई कॉल का उपयोग करने के लिए अंतिम () विधि बना रहा था।


3

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

कई डेटाबेस ड्राइवर डेवलपर्स के खिलाफ थोड़ी सुरक्षा प्रदान करने के लिए अपने स्टेटमेंट और कनेक्शन कार्यान्वयन में ऐसा करते हैं जो उन पर कॉल करना भूल जाते हैं।


2

संपादित करें: ठीक है, यह वास्तव में काम नहीं करता है। मैंने इसे लागू किया और सोचा कि अगर यह कभी-कभी विफल हो जाता है तो मेरे लिए ठीक है, लेकिन इसने अंतिम बार विधि को एक बार भी कॉल नहीं किया।

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

@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}

मुझे लगता है कि एक कैश (डिस्क पर आप जिस प्रकार से फ्लश करेंगे) एक अच्छा उदाहरण है। और भले ही अंतिम रूप से नहीं कहा जाता है, कोई पसीना नहीं।
फू

2

यह उन चीजों को हटाने के लिए आसान हो सकता है जिन्हें एक वैश्विक / स्थिर स्थान (आवश्यकता से बाहर) में जोड़ा गया है, और ऑब्जेक्ट को हटाए जाने पर हटाए जाने की आवश्यकता है। उदाहरण के लिए:

    निजी शून्य addGlobalClickListener () {
        weakAwtEventListener = नया WeakAWTEventListener (यह);

        Toolkit.getDefaultToolkit ()। AddAWTEventListener (weakAwtEventListener, AWTEvent.MOUSE_EVENT_MASK);
    }

    @Override
    संरक्षित शून्य को अंतिम रूप दें () फेंकता है {
        super.finalize ();

        अगर (कमज़ोर एवेंटिस्टलिस्ट! = अशक्त) {
            । Toolkit.getDefaultToolkit () removeAWTEventListener (weakAwtEventListener);
        }
    }

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

0

iirc - आप महंगे संसाधनों के लिए पूलिंग तंत्र को लागू करने के साधन के रूप में अंतिम विधि का उपयोग कर सकते हैं - इसलिए उन्हें GC भी नहीं मिलता है।


0

अलग नोट के रूप में:

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

स्रोत: अंतिम-() जावा -9 पर पदावनत


0

संसाधनों (फाइल, सॉकेट, स्ट्रीम आदि) को एक बार बंद करने की आवश्यकता है, क्योंकि हम उनके साथ काम कर रहे हैं। उनके पास आम तौर पर वह close()विधि होती है जिसे हम आम तौर पर बयानों के finallyअनुभाग में कहते हैं try-catch। कभी कभीfinalize() कुछ डेवलपर्स द्वारा भी उपयोग किया जा सकता है लेकिन IMO एक उपयुक्त तरीका नहीं है क्योंकि इस बात की कोई गारंटी नहीं है कि अंतिम रूप हमेशा कहा जाएगा।

जावा 7 में हमें कोशिश के साथ संसाधनों का विवरण मिला है जिसका उपयोग किया जा सकता है:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  // Processing and other logic here.
} catch (Exception e) {
  // log exception
} finally {
  // Just in case we need to do some stuff here.
}

उपरोक्त उदाहरण में try-with-resource स्वचालित रूप BufferedReaderसे इनवॉइस close()विधि द्वारा संसाधन बंद कर देगा । यदि हम चाहें तो हम अपनी कक्षाओं में क्लोजेबल को भी लागू कर सकते हैं और उसी तरह से इसका उपयोग कर सकते हैं। IMO यह अधिक साफ और सरल लगता है।


0

व्यक्तिगत रूप से, मैं लगभग कभी भी finalize()एक दुर्लभ परिस्थिति को छोड़कर उपयोग नहीं करता हूं: मैंने एक कस्टम सामान्य प्रकार का संग्रह बनाया, और मैंने एक कस्टम finalize()विधि लिखी जो निम्नलिखित कार्य करती है:

public void finalize() throws Throwable {
    super.finalize();
    if (destructiveFinalize) {
        T item;
        for (int i = 0, l = length(); i < l; i++) {
            item = get(i);
            if (item == null) {
                continue;
            }
            if (item instanceof Window) {
                ((Window) get(i)).dispose();
            }
            if (item instanceof CompleteObject) {
                ((CompleteObject) get(i)).finalize();
            }
            set(i, null);
        }
    }
}

( CompleteObjectएक अंतरफलक आपके द्वारा निर्दिष्ट आप शायद ही कभी लागू से लागू किया है देता है कि मैंने बनाया है Objectतरीकों की तरह #finalize(), #hashCode()है, और #clone())

इसलिए, एक बहन #setDestructivelyFinalizes(boolean)विधि का उपयोग करते हुए, मेरे संग्रह का उपयोग करने वाला प्रोग्राम (सहायता) गारंटी दे सकता है कि इस संग्रह के संदर्भ को नष्ट करने से इसकी सामग्री के संदर्भ भी नष्ट हो जाते हैं और किसी भी विंडोज़ को डिस्पोज कर देते हैं जो जेवीएम को अनायास ही जीवित रख सकते हैं। मैंने माना कि किसी भी धागे को रोकना है, लेकिन इससे कीड़े की एक पूरी नई कैन खुल गई है।


4
finalize()आपके CompleteObjectउदाहरणों पर कॉल करना जैसे कि आप उपरोक्त कोड में करते हैं कि इसे दो बार कहा जा सकता है, क्योंकि JVM अभी भी finalize()एक बार इन वस्तुओं को वास्तव में पहुंच से बाहर हो जाने पर आह्वान कर सकता है, जो अंतिम रूप देने के तर्क के कारण आपके विशेष संग्रह की विधि से पहले हो सकता है। finalize()एक ही समय में बुलाया या समवर्ती। चूंकि मुझे आपकी विधि में थ्रेड सुरक्षा सुनिश्चित करने के लिए कोई उपाय नहीं दिखता है, इसलिए आप इस बात से अनजान हैं ...
Holger

0

स्वीकृत उत्तर सूचियों को अंतिम रूप देने के दौरान संसाधन बंद करना हो सकता है।

हालाँकि यह उत्तर दर्शाता है कि JIT8 में कम से कम JIT कंपाइलर के साथ, आप अनपेक्षित मुद्दों में भाग लेते हैं, जहाँ कभी-कभी फ़ाइनलीज़र को आपके ऑब्जेक्ट द्वारा बनाए गए स्ट्रीम से रीडिंग खत्म करने से पहले भी बुलाया जाता है।

तो उस स्थिति में भी अंतिम रूप देने की सिफारिश नहीं की जाएगी।


यह काम करेगा, यदि ऑपरेशन को थ्रेड सुरक्षित किया जाता है, जो कि एक जरूरी है, क्योंकि फाइनल को मनमाने ढंग से धागे कहा जा सकता है। चूंकि सही ढंग से लागू धागा सुरक्षा का तात्पर्य है कि न केवल करीबी ऑपरेशन, बल्कि संसाधन का उपयोग करने वाले संचालन को एक ही ऑब्जेक्ट या लॉक पर सिंक्रनाइज़ करना होगा, उपयोग और करीबी ऑपरेशन के बीच एक संबंध होता है, जो बहुत जल्दी रोकता है अंतिम रूप देने के। लेकिन, निश्चित रूप से, पूरे उपयोग के लिए एक उच्च कीमत पर ...
Holger
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.