जावा में अंतिम रूप () विधि को कब कहा जाता है?


330

मुझे यह जानना चाहिए कि finalize()विधि को कब बुलाया जाता है JVM। मैंने एक परीक्षण वर्ग बनाया जो एक फाइल में लिखता है जब finalize()विधि को ओवरराइड करके बुलाया जाता है। इसे अंजाम नहीं दिया जाता है। क्या कोई मुझे इसका कारण बता सकता है कि यह क्यों नहीं चल रहा है?


34
बस एक साइड नोट के रूप में: अंतिम रूप में जावा 9 में पदावनत के रूप में चिह्नित किया गया है
Reg

1
एक बार देखें: infoq.com/news/2017/03/Java-Finalize-Deprecated
wleao

यदि किसी चीज में आपकी वस्तु या यहां तक ​​कि कक्षा का संदर्भ है। finalize()और कचरा संग्रह का कोई प्रभाव नहीं पड़ता है।
ha9u63ar

जवाबों:


273

सामान्य तौर पर finalize()किसी भी सफाई आदि पर भरोसा करना सबसे अच्छा नहीं है ।

जावदोक के अनुसार (जो पढ़ने लायक होगा), यह है:

कचरा संग्रहकर्ता द्वारा किसी वस्तु पर तब कॉल किया जाता है जब कचरा संग्रह यह निर्धारित करता है कि वस्तु के लिए अधिक संदर्भ नहीं हैं।

जैसा कि जोआचिम ने कहा था, किसी कार्यक्रम के जीवन में ऐसा कभी नहीं हो सकता है यदि वस्तु हमेशा सुलभ हो।

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


19
दूसरे शब्दों में (केवल भविष्य के पाठकों के लिए स्पष्ट करने के लिए) इसे मुख्य वर्ग पर कभी नहीं बुलाया जाता है, जैसे कि, जब मुख्य वर्ग बंद हो जाता है, तो कोई कचरा एकत्र करने की आवश्यकता नहीं होती है। ओएस वैसे भी उपयोग किए गए ऐप को साफ करता है।
मार्क जेरोनिमस

113
"उपयोग करने के लिए सबसे अच्छा तरीका नहीं है ... जब तक कि कुछ विशिष्ट आपके लिए आवश्यक न हो" - उह, यह वाक्य 100% सब कुछ पर लागू होता है, इसलिए यह उपयोगी नहीं है। जोआचिम सॉर का उत्तर बहुत बेहतर है
बीटी

1
@ Zom-B आपका उदाहरण स्पष्टीकरण के लिए सहायक है, लेकिन सिर्फ पांडित्यपूर्ण होने के लिए, संभवतः इसे मुख्य वर्ग पर बुलाया जा सकता है यदि मुख्य वर्ग एक गैर-डेमॉन थ्रेड बनाता है और फिर लौटता है?
टॉम जी

3
तो ऐसी स्थितियाँ क्या हैं जहाँ finalizeउपयोगी होगी?
नबंर

3
@MarkJeronimus - वास्तव में, यह अप्रासंगिक है। finalize()मुख्य वर्ग के लिए विधि का उपयोग तब किया जाता है जब वर्ग का एक >> उदाहरण << एकत्र किया जाता है, न कि जब मुख्य विधि समाप्त हो जाती है। और इसके अलावा, आवेदन समाप्त होने से पहले मुख्य वर्ग कचरा एकत्र किया जा सकता है; उदाहरण के लिए एक बहु-थ्रेडेड ऐप में जहां "मुख्य" धागा अन्य थ्रेड बनाता है और फिर लौटता है। (व्यवहार में, एक गैर-मानक क्लास लोडर की आवश्यकता होगी ....)
स्टीफन सी

379

finalizeविधि कहा जाता है एक वस्तु के बारे में कचरा एकत्र करने के लिए है जब है। कचरा संग्रहण के लिए पात्र होने के बाद यह किसी भी समय हो सकता है।

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

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

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


2
@Rajesh। नहीं, यह "जीवन काल" का मुद्दा नहीं है। आप अपने कार्यक्रम को एक अनंत लूप (वर्षों के लिए) में रख सकते हैं, और यदि कचरा कलेक्टर की आवश्यकता नहीं है, तो यह कभी नहीं चलेगा।
क्रिसकंट्रेल

5
@VikasVerma: सही प्रतिस्थापन कुछ भी नहीं है: आपको उनकी आवश्यकता नहीं होनी चाहिए। एक ही मामला जहां यह समझ में आता है कि अगर आपकी कक्षा कुछ बाहरी संसाधन (जैसे टीसीपी / आईपी कनेक्शन, फ़ाइल ... कुछ भी प्रबंधित करती है, जो जावा जीसी संभाल नहीं सकती है)। उन मामलों में Closableइंटरफ़ेस (और इसके पीछे का विचार) शायद वही है जो आप चाहते हैं: .close()संसाधन को बंद करें / त्यागें और अपनी कक्षा के उपयोगकर्ता को सही समय पर कॉल करने की आवश्यकता है। आप हो सकता है एक जोड़ना चाहते हैं finalizeविधि "बस को बचाने के लिए", लेकिन वह एक वास्तविक ठीक से एक डीबगिंग उपकरण के और अधिक हो सकता है (क्योंकि यह विश्वसनीय पर्याप्त नहीं है)।
जोकिम सोउर

4
@ वैवाहिक: यह वास्तव में एक बहुत अलग सवाल है और अलग से पूछा जाना चाहिए। शटडाउन हुक हैं, लेकिन अगर जेवीएम अप्रत्याशित रूप से (उर्फ क्रैश) बंद हो जाता है तो उनकी गारंटी नहीं है। लेकिन फाइनल के लिए उनकी गारंटी काफी मजबूत है (और वे सुरक्षित भी हैं)।
जोकिम सॉयर

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

2
फाइनलर्स कभी-कभी दिन बचा सकते हैं ... मेरे पास एक ऐसा मामला था जहां एक 3 पार्टी लाइब्रेरी FileInputStream का उपयोग कर रही थी, इसे कभी भी बंद नहीं किया। मेरा कोड लाइब्रेरी के कोड को कॉल कर रहा था, और फिर असफल होने के कारण फ़ाइल को स्थानांतरित करने का प्रयास किया गया। मुझे System.gc()FileInputStream :: को अंतिम रूप देने () के लिए कॉल करने के लिए मजबूर होना पड़ा , फिर मैं फ़ाइल को स्थानांतरित कर सका।
एलिस्ट

73
protected void finalize() throws Throwable {}
  • हर वर्ग finalize()java.lang.Object से विधि प्राप्त करता है
  • विधि को कचरा कलेक्टर द्वारा तब बुलाया जाता है जब यह निर्धारित करता है कि वस्तु का कोई और संदर्भ मौजूद नहीं है
  • ऑब्जेक्ट फ़ाइनल विधि कोई क्रिया नहीं करती है, लेकिन इसे किसी भी वर्ग द्वारा ओवरराइड किया जा सकता है
  • आम तौर पर गैर-जावा संसाधनों को साफ करने के लिए इसे ओवरराइड किया जाना चाहिए अर्थात फाइल बंद करना
  • यदि ओवरराइडिंग है finalize()तो कोशिश-कैच-एंड स्टेटमेंट का उपयोग करना और हमेशा कॉल करना अच्छा प्रोग्रामिंग अभ्यास है super.finalize()। यह सुनिश्चित करने के लिए एक सुरक्षा उपाय है कि आप अनजाने में ऑब्जेक्ट कॉलिंग क्लास द्वारा उपयोग किए गए संसाधन को बंद करने से न चूकें

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • finalize()कचरा संग्रहण के दौरान फेंके गए किसी भी अपवाद को अंतिम रूप दिया जाता है, लेकिन इसे अनदेखा कर दिया जाता है

  • finalize() किसी भी वस्तु पर एक से अधिक बार नहीं चलाया जाता है

से उद्धृत: http://www.janeg.ca/scjp/gc/finalize.html

आप इस लेख को भी देख सकते हैं:


25
आपके द्वारा लिंक किया गया JavaWorld लेख 1998 से है, और इसमें कुछ दिलचस्प सलाह है, विशेष रूप से सुझाव है कि JVM से बाहर निकलने से पहले अंतिम रूप से चलने के लिए System.runFinalizersOnExit () को कॉल करें। यह विधि वर्तमान में पदावनत है, टिप्पणी के साथ 'यह विधि स्वाभाविक रूप से असुरक्षित है। इसका परिणाम यह हो सकता है कि अंतिम रूप से जीवित वस्तुओं पर कॉल किया जा रहा है, जबकि अन्य धागे उन वस्तुओं को समवर्ती रूप से जोड़-तोड़ कर रहे हैं, जिसके परिणामस्वरूप अनिश्चित या अजीब व्यवहार होता है। ' इसलिए मैं ऐसा नहीं करूंगा।
ग्रेग चबाला

3
चूँकि runFinalizerOnExit () थ्रेड-सुरक्षित नहीं है, जो कोई भी कर सकता है, वह Runtime.getRimeime () है। AddShutdownHook (नया थ्रेड () {public void run () {विध्वंसक्लिप्सिंगक्लास ()}};); वर्ग के निर्माता में।
उस्मान संगत

2
@Ustaman Sangat यह करने का एक तरीका है, लेकिन यह याद रखें कि यह आपके उदाहरण के लिए शटडाउन हूक से सेट करता है, जो बहुत अधिक गारंटी देता है कि आपकी कक्षा कभी कचरा एकत्र नहीं करती है। दूसरे शब्दों में, यह एक मेमोरी लीक है।
भेदी

1
@pieroxy, जबकि मैं किसी और चीज के लिए अंतिम रूप () का उपयोग नहीं करने के बारे में यहां सभी से सहमत हूं, मैं यह नहीं देखता कि शटडाउन हुक से एक संदर्भ क्यों होगा। एक नरम संदर्भ हो सकता है।
उस्मान संगत

25

जावा finalize()विधि एक विध्वंसक नहीं है और इसका उपयोग तर्क को संभालने के लिए नहीं किया जाना चाहिए जो आपके आवेदन पर निर्भर करता है। जावा की कल्पना में कहा गया है कि इस बात की कोई गारंटी नहीं है कि finalizeआवेदन के लाइव होने के दौरान विधि को बुलाया जाता है।

जैसा कि आप चाहते हैं कि एक संयोजन finallyऔर सफाई विधि है, जैसे:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

    if (null != myObj) {
        myObj.cleanup();
    }
}

20

प्रभावी जावा, दूसरा संस्करण पृष्ठ 27 देखें। आइटम 7: फाइनल से बचें

फाइनल अप्रत्याशित, अक्सर खतरनाक और आम तौर पर अनावश्यक होते हैं। एक फाइनल में कुछ भी समय महत्वपूर्ण नहीं है। महत्वपूर्ण स्थायी स्थिति को अद्यतन करने के लिए कभी भी एक अंतिम रूप पर निर्भर न करें।

किसी संसाधन को समाप्त करने के लिए, इसके बजाय अंततः प्रयास करें:

// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
    // Do what must be done with foo
    ...
} finally {
    foo.terminate(); // Explicit termination method
}

3
या संसाधनों के साथ कोशिश का उपयोग करें
गेब्रियल गार्सिया

3
यह मानता है कि एक वस्तु का जीवनकाल एक कार्य के दायरे में है। जो, ज़ाहिर है, ऐसा नहीं है कि ओपी का जिक्र है और न ही यह मूल रूप से किसी की ज़रूरत है। "कैश इंजन रिटर्न वैल्यू संदर्भ गणना" सोचें। आप अंतिम प्रविष्टि के मुक्त होने पर कैश प्रविष्टि को मुक्त करना चाहते हैं, लेकिन आपको पता नहीं है कि अंतिम रेफरी को कब मुक्त किया गया है। अंतिम रूप () उदाहरण के लिए, एक रेफरी संख्या को घटा सकते हैं ... लेकिन यदि आपको अपने उपयोगकर्ताओं को स्पष्ट रूप से एक मुफ्त फ़ंक्शन की आवश्यकता होती है, तो आप मेमोरी लीक के लिए पूछ रहे हैं। आमतौर पर मैं सिर्फ दोनों (रिलीज फंक्शन + डबल चेक को अंतिम रूप देता हूं ...) ...
एरिक एरोनिटी

16

finalize()जावा में विधि को कब कहा जाता है?

जीसी का पता लगाने के बाद अंतिम विधि को कहा जाएगा कि ऑब्जेक्ट अब उपलब्ध नहीं है, और इससे पहले कि वह वास्तव में ऑब्जेक्ट द्वारा उपयोग की जाने वाली मेमोरी को पुनः प्राप्त करता है।

  • यदि कोई वस्तु कभी अप्राप्य नहीं बनती है, तो finalize()उस पर कभी भी कॉल नहीं किया जाएगा।

  • यदि GC नहीं चलता है, तो finalize()उसे कभी नहीं बुलाया जा सकता है। (आम तौर पर, जीसी केवल तब चलता है जब जेवीएम यह तय करता है कि इसे सार्थक बनाने के लिए पर्याप्त कचरा होने की संभावना है।)

  • जीसी निर्धारित करने से पहले यह एक से अधिक जीसी चक्र ले सकता है कि एक विशिष्ट वस्तु पहुंच से बाहर है। (जावा GCs आमतौर पर "जेनरेशनल" कलेक्टर हैं ...)

  • एक बार जब GC का पता चलता है कि कोई वस्तु पहुंच से बाहर है और अंतिम रूप देने योग्य है, तो यह अंतिम रूप देने वाली कतार पर स्थित है। आमतौर पर अंतिम रूप से सामान्य जीसी के साथ अतुल्यकालिक रूप से होता है।

(JVM कल्पना वास्तव में एक JVM को कभी भी अंतिम रूप से चलाने की अनुमति नहीं देती है ... बशर्ते कि यह वस्तुओं द्वारा उपयोग किए जाने वाले स्थान को पुनः प्राप्त नहीं करता है। इस तरह से लागू किया गया एक JVM अपंग / बेकार होगा, लेकिन यह इस व्यवहार की अनुमति है " ।)

उतावलापन यह है कि उन चीजों को करने के लिए अंतिम रूप देने पर भरोसा करना नासमझी है जिन्हें एक निश्चित समय-सीमा में किया जाना है। उनका उपयोग न करना ही "सर्वोत्तम अभ्यास" है। finalize()विधि में जो आप करने की कोशिश कर रहे हैं उसे करने के लिए एक बेहतर (यानी अधिक विश्वसनीय) तरीका होना चाहिए ।

अंतिम रूप के लिए एकमात्र वैध उपयोग वस्तुओं के साथ जुड़े संसाधनों को साफ करना है जो आवेदन कोड द्वारा खो दिए गए हैं। फिर भी, आपको एप्लिकेशन कोड लिखने का प्रयास करना चाहिए ताकि यह पहले स्थान पर वस्तुओं को न खोए। (उदाहरण के लिए, यह सुनिश्चित करने के लिए जावा 7+ कोशिश-के-संसाधनों का उपयोग करें कि close()हमेशा कहा जाता है ...)


मैंने एक परीक्षण वर्ग बनाया, जो एक फाइल में लिखता है जब अंतिम () विधि को ओवरराइड करके बुलाया जाता है। इसे अंजाम नहीं दिया जाता है। क्या कोई मुझे इसका कारण बता सकता है कि यह क्यों नहीं चल रहा है?

यह कहना मुश्किल है, लेकिन कुछ संभावनाएं हैं:

  • ऑब्जेक्ट कचरा एकत्र नहीं है क्योंकि यह अभी भी उपलब्ध है।
  • ऑब्जेक्ट कचरा एकत्र नहीं किया जाता है क्योंकि जीसी आपके परीक्षण खत्म होने से पहले नहीं चलता है।
  • ऑब्जेक्ट GC द्वारा पाया जाता है और GC द्वारा अंतिम रूप देने वाली कतार में रखा जाता है, लेकिन अंतिम परीक्षण आपके परीक्षण के पूरा होने से पहले पूरा नहीं होता है।

10

चूँकि JVM द्वारा अंतिम रूप () पद्धति को कॉल करने में अनिश्चितता है (निश्चित नहीं है कि अंतिम रूप दिया गया है या नहीं) जिसे निष्पादित किया जाएगा या नहीं), अध्ययन के उद्देश्यों के लिए यह देखने का बेहतर तरीका है कि अंतिम रूप से क्या होता है () कहा जाता है। JVM को कमांड द्वारा कचरा संग्रहण के लिए मजबूर करें System.gc()

विशेष रूप से, अंतिम रूप से () कहा जाता है जब कोई वस्तु अब उपयोग में नहीं है। लेकिन जब हम नई वस्तुओं का निर्माण करके इसे कॉल करने का प्रयास करते हैं तो इसकी कॉल की कोई निश्चितता नहीं होती है। तो निश्चितता के लिए हम एक ऐसी nullवस्तु बनाते हैं cजिसका स्पष्ट रूप से कोई भविष्य में उपयोग नहीं होता है, इसलिए हम वस्तु को cअंतिम रूप देते हैं।

उदाहरण

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

उत्पादन

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

नोट - 70 तक प्रिंट करने और उसके बाद भी प्रोग्राम में ऑब्जेक्ट बी का उपयोग नहीं किया जा रहा है, अनिश्चितता है कि जेवीएम द्वारा बी क्लीयर किया गया है या नहीं "क्लास बाइक में कॉल की गई अंतिम विधि ..." प्रिंट नहीं है।


10
कॉलिंग System.gc();की गारंटी नहीं है कि कचरा संग्रह वास्तव में चलाया जाएगा।
साइमन फोर्सबर्ग

3
यह भी गारंटी नहीं है कि किस तरह का संग्रह चलाया जाएगा। अधिकांश जावा जीसी के बाद से प्रासंगिक "जेनरेशनल" कलेक्टर हैं।
स्टीफन C

5

अंतिम रूप वर्ग निर्माण के लिए गिनती का प्रिंट आउट लेगा।

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

मुख्य

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

जैसा कि आप देख सकते हैं। क्लास के 36 नंबर होने के बाद पहली बार नीचे दिखाए गए gc को निष्पादित किया गया।

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F

4

अंतिम रूप से अंतिम तरीके के साथ कुश्ती करना (परीक्षण के दौरान कनेक्शन पूल को हटाने के लिए), मेरा कहना है कि अंतिम रूप में कई चीजों का अभाव है। VisualVM का उपयोग करने के साथ-साथ वास्तविक बातचीत को ट्रैक करने के लिए कमजोर संदर्भों का उपयोग करने के लिए मैंने पाया है कि निम्नलिखित चीजें जावा 8 वातावरण में सच हैं (Oracle JDK, Ubuntu 15):

  • अंतिम रूप को तुरंत फाइनल नहीं कहा जाता है (जीसी भाग) व्यक्तिगत रूप से संदर्भ का स्वामी होता है
  • डिफ़ॉल्ट कचरा कलेक्टर पूल में अनुपलब्ध वस्तुएं होती हैं
  • अंतिम रूप से बल्क को एक कार्यान्वयन विवरण की ओर इशारा करते हुए कहा जाता है कि एक निश्चित चरण है जहां कचरा कलेक्टर संसाधनों को मुक्त करता है।
  • System.gc () को कॉल करने से अक्सर वस्तुओं को अधिक बार अंतिम रूप नहीं दिया जाता है, यह केवल अंतिम रूप से परिणाम होता है जो एक पहुंच योग्य वस्तु के बारे में अधिक तेज़ी से अवगत कराता है
  • ढेर डंप या किसी अन्य आंतरिक तंत्र के प्रदर्शन के दौरान उच्च ढेर ओवरहेड के कारण लगभग हमेशा परिणामस्वरूप थ्रेड डंप का निर्माण होता है
  • अंतिमकरण सीम या तो मेमोरी आवश्यकताओं (अधिक मेमोरी मुक्त) या एक निश्चित आंतरिक सीमा के अंतिमकरण के लिए चिह्नित की जा रही वस्तुओं की सूची द्वारा बाध्य किया जाता है। इसलिए यदि आपके पास बहुत सी वस्तुएं हैं जिन्हें अंतिम रूप दिया जा रहा है तो अंतिम चरण को अधिक बार और पहले ट्रिगर किया जाएगा जब केवल कुछ के साथ तुलना की जाएगी
  • ऐसी परिस्थितियाँ थीं जब एक System.gc () ने सीधे अंतिम रूप दिया, लेकिन केवल तभी जब संदर्भ एक स्थानीय और अल्पकालिक था। यह पीढ़ी से संबंधित हो सकता है।

फाइनल थॉट

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


2

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

  1. उस ऑब्जेक्ट के सभी संदर्भ स्पष्ट रूप से उदाहरण के लिए सेट करने के लिए उदा। ऑब्जेक्ट = अशक्त
  2. ऑब्जेक्ट एक ब्लॉक के अंदर बनाया जाता है और संदर्भ उस ब्लॉक से बाहर निकलते ही दायरे से बाहर हो जाता है।
  3. मूल ऑब्जेक्ट शून्य पर सेट होता है, यदि कोई ऑब्जेक्ट किसी अन्य ऑब्जेक्ट का संदर्भ रखता है और जब आप कंटेनर ऑब्जेक्ट का संदर्भ शून्य सेट करते हैं, तो बच्चा या निहित ऑब्जेक्ट स्वचालित रूप से कचरा संग्रह के लिए योग्य हो जाता है।
  4. यदि किसी ऑब्जेक्ट में केवल WeakHashMap के माध्यम से लाइव संदर्भ हैं, तो यह कचरा संग्रह के लिए योग्य होगा।

यदि किसी finalऑब्जेक्ट का फ़ील्ड धीमी गणना के दौरान बार-बार उपयोग किया जाता है, और ऑब्जेक्ट का उपयोग उसके बाद कभी नहीं किया जाएगा, तो क्या ऑब्जेक्ट को तब तक जीवित रखा जाएगा, जब तक कि अंतिम स्रोत कोड फ़ील्ड का अनुरोध नहीं करता है, या JIT फ़ील्ड को कॉपी नहीं कर सकता है अस्थायी चर और फिर गणना से पहले वस्तु को छोड़ दें?
सुपरकैट

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

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

@ सुपरकैट: जेआईटी अंतिम रूप से फायर नहीं करता है, यह सिर्फ एक संदर्भ नहीं रखने के लिए कोड की व्यवस्था करता है, हालांकि, यह सीधे एनक्यूई करने के लिए फायदेमंद हो सकता है FinalizerReference, ताकि यह पता लगाने के लिए जीसी चक्र की आवश्यकता न हो कि कोई भी नहीं है संदर्भ। एक होने से पहले संबंध सुनिश्चित करने के लिए सिंक्रनाइज़ेशन पर्याप्त है ; चूंकि अंतिम रूपकरण (वास्तव में) एक अलग धागे में चल रहा है, यह अक्सर औपचारिक रूप से वैसे भी आवश्यक होता है। जावा 9 जोड़ने जा रहा है Reference.reachabilityFence...
होल्गर

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

2

अंतिम विधि की गारंटी नहीं है। यह विधि उस समय कहलाती है जब ऑब्जेक्ट GC के लिए योग्य हो जाता है। ऐसी कई स्थितियाँ हैं जहाँ वस्तुओं को एकत्र नहीं किया जा सकता है।


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

2

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

protected void finalize(){
    // This is where the finalization code is entered
}

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


1

कक्षा जहां हम अंतिम विधि को ओवरराइड करते हैं

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

अंतिम विधि की संभावना कहा जा रहा है

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

जब मेमोरी को डंप ऑब्जेक्ट्स के साथ ओवरलोड किया जाता है, तो जीसी अंतिम विधि कहेगा

कंसोल को देखें और देखें, जहां आपको अंतिम रूप से बार-बार कॉल की जाने वाली अंतिम विधि नहीं मिलती है, जब मेमोरी ओवरलोड हो रही है तो अंतिम विधि कहा जाएगा।


0

जावा वस्तुओं को अंतिम रूप देने के लिए एक विधि को लागू करने की अनुमति देता है () जिसे कहा जा सकता है।

अंतिम रूप () विधि कहा जाता है अगर कचरा संग्रहकर्ता वस्तु को इकट्ठा करने की कोशिश करता है।

यदि कचरा संग्रहकर्ता नहीं चलता है, तो विधि को कॉल नहीं किया जाता है।

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

व्यवहार में, आप वास्तविक परियोजनाओं में इसका उपयोग करने की अत्यधिक संभावना नहीं है।

बस ध्यान रखें कि इसे कॉल नहीं किया जा सकता है और यह निश्चित रूप से दो बार नहीं कहा जाएगा। अंतिम रूप () विधि शून्य या एक बार चल सकती है।

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

स्रोत


0

finalize()कचरा संग्रहण से ठीक पहले कहा जाता है। किसी वस्तु के दायरे से बाहर जाने पर इसे नहीं कहा जाता है। इसका मतलब यह है कि आपको पता नहीं चल सकता है कि कब या क्या किया finalize()जाएगा।

उदाहरण:

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


0

जैसा कि https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers में बताया गया है ,

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


-3

बेहतर समझ के लिए इस कार्यक्रम को चलाने की कोशिश करें

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.