2010-03-15 14 views
9

अंतिम रूप देने की मेरी समझ यह है:जावा में अंतिम रूप देने का उद्देश्य क्या है?

किसी ऑब्जेक्ट पर मौजूद स्मृति को साफ़ या पुनः प्राप्त करने के लिए, कचरा कलेक्टर कार्रवाई में आता है। (स्वचालित रूप से लागू किया जाता है?)

कचरा कलेक्टर तब ऑब्जेक्ट को अस्वीकार करता है। कभी-कभी, ऑब्जेक्ट तक पहुंचने के लिए कचरा कलेक्टर के लिए कोई रास्ता नहीं है। फिर अंतिम सफाई प्रक्रिया को अंतिम रूप देने के लिए बुलाया जाता है जिसके बाद कचरा कलेक्टर लगाया जा सकता है।

क्या यह अंतिमकरण का सटीक वर्णन है?

उत्तर

15

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

अंतिमकरण वस्तु द्वारा अधिग्रहित संसाधनों को साफ करने के लिए था (स्मृति नहीं, बल्कि अन्य संसाधन, जैसे फाइल हैंडल, बंदरगाह, डीबी कनेक्शन इत्यादि)। हालांकि, यह वास्तव में :-(

  • यह अप्रत्याशित है जब finalize()
  • वास्तव में
  • बुलाया जाएगा ऐसा नहीं हो पाया है, वहाँ कोई गारंटी नहीं है कि finalize() कभी बुलाया जाएगा है!

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

6

नहीं। finalize() विधि केवल तब चलती है जब कचरा कलेक्टर आपके ऑब्जेक्ट को पुनः प्राप्त करने का प्रयास करता है।

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

+1

आप यह नहीं कह सकते हैं "यदि और केवल यदि"; आप "केवल अगर" कह सकते हैं, लेकिन इस बात की कोई गारंटी नहीं है कि इसे बिल्कुल भी बुलाया जाएगा। –

+0

@mmyers: +1। पुनः दावा -> अंतिम रूप दिया गया है, लेकिन विपरीत नहीं है। – danben

+0

वहां कोई "लेकिन" नहीं है: यदि जीसी स्मृति को पुनः प्राप्त करने का प्रयास करता है, तो अंतिम() को कॉल किया जाता है। –

7
this article से

:

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

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

इसके अलावा, this article सूर्य से प्रक्रिया को समझाते हुए कुछ अच्छे चित्र हैं।

5

वास्तव में, यहाँ अंतिम रूप देने() विधि का व्यवहार है:

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

इसके अलावा, कुछ लोगों ने प्रदर्शन परीक्षण किए हैं और दिखाया है कि अंतिम विधि कुछ वस्तु के निर्माण/विनाश को धीमा कर देती है। मुझे स्रोत याद नहीं है इसलिए इस जानकारी का बहुत विश्वसनीय नहीं है। :)

+0

फाइनलर्स ने एनआईओ में प्रदर्शन समस्याओं का कारण बना दिया। उन्हें 1.4.1 (या संभवतः 1.4.2) में हटा दिया गया था। यदि आप एनआईओ का उपयोग कर रहे हैं, तो आपको उम्मीद है कि 'आखिरकार' सही तरीके से उपयोग कैसे किया जाए। –

2

अंतिमकरण संसाधनों को साफ करने के लिए उपयोग किया जाता है, जिसे कचरा कलेक्टर द्वारा मुक्त नहीं किया जा सकता है। उदाहरण के लिए, ओएस से सीधे संसाधनों को आवंटित करें (कुछ native एपीआई के माध्यम से) संसाधन।

class Wrapper { 
    private long handle; 

    private Handle(long h) { 
     handle = h; 
    } 

    private static native long getHandleFromOS(); 

    static Wrapper allocate() { 
     return new Handle(getHandleFromOS()); 
    } 
} 

तो, क्या होता है, अपने कोड वर्ग Wrapper का एक उदाहरण आवंटित करता है, तो: यह आमतौर पर "संभाल" (एक UNIX फ़ाइल वर्णनकर्ता या Windows हैंडल, या कुछ इसी तरह) किसी तरह का पैदावार? वैसे कक्षा किसी प्रकार के ओएस विशिष्ट संसाधन आवंटित करती है और सदस्य चर में इसका संदर्भ रखती है (हैंडल)। लेकिन क्या होता है, जब एक रैपर उदाहरण के लिए अंतिम जावा संदर्भ खो जाता है? अब, कचरा कलेक्टर (कुछ बिंदु पर) अब निष्क्रिय निष्क्रिय रैपर उदाहरण की जगह पुनः प्राप्त करेगा। लेकिन रैपर द्वारा आवंटित ओएस संसाधन का क्या होता है? यह उपरोक्त परिदृश्य में लीक हो जाएगा, जो एक बुरी चीज है, अगर यह एक महंगा संसाधन है, जैसे फाइल डिस्क्रिप्टर।

इस तरह के परिदृश्य में आपके कोड को साफ़ करने की अनुमति देने के लिए, finalize विधि है।

class Wrapper { 
    private long handle; 

    private Handle(long h) { 
     handle = h; 
    } 

    protected void finalize() { 
     returnHandleToOS(handle); 
    } 

    private static native long getHandleFromOS(); 
    private static native void returnHandleToOS(long handle); 

    static Wrapper allocate() { 
     return new Handle(getHandleFromOS()); 
    } 
} 

अब, जब जी सी एक आवरण उदाहरण के अंतरिक्ष reclaims, finalizer सुनिश्चित करें कि संसाधन ठीक से ओएस में लौट जाता है बनाता है।

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

class Wrapper { 
    private long handle; 

    private Handle(long h) { 
     handle = h; 
    } 

    protected void finalize() { 
     if(handle != 0) returnHandleToOS(handle); 
    } 

    public void dispose() { 
     returnHandleToOS(handle); 
     handle = 0; 
    } 

    private static native long getHandleFromOS(); 
    private static native void returnHandleToOS(long handle); 

    static Wrapper allocate() { 
     return new Handle(getHandleFromOS()); 
    } 
} 
संबंधित मुद्दे