java - क्या जावा के लिए कोई विनाशक है?




destructor (13)

अगर यह सिर्फ स्मृति है तो आप चिंतित हैं, नहीं। बस जीसी पर भरोसा करें यह एक सभ्य नौकरी करता है। मैंने वास्तव में इतना कुशल होने के बारे में कुछ देखा कि कुछ मामलों में बड़े सरणी का उपयोग करने के बजाय प्रदर्शन के लिए छोटे वस्तुओं के ढेर बनाने के लिए यह बेहतर हो सकता है।

क्या जावा के लिए कोई विनाशक है? मुझे इस पर कोई दस्तावेज नहीं मिल रहा है। यदि नहीं है, तो मैं एक ही प्रभाव कैसे प्राप्त कर सकता हूं?

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

आम तौर पर एक सी / सी ++ प्रोग्रामर होने के नाते, मैंने सोचा कि यह लागू करने के लिए तुच्छ होगा। (और इसलिए मैंने इसे अंतिम रूप से कार्यान्वित करने की योजना बनाई।) मैंने अपने कार्यक्रम को संरचित किया है कि सभी 'रीसेट-सक्षम' ऑब्जेक्ट एक ही कक्षा में होंगे ताकि रीसेट बटन दबाए जाने पर मैं बस 'लाइव' ऑब्जेक्ट्स को नष्ट कर सकूं।

मैं सोच रहा था, अगर मैंने जो कुछ किया है, वह सिर्फ डेटा को कम करने और कचरा कलेक्टर को इकट्ठा करने का इंतजार कर रहा था, तो क्या मेरे उपयोगकर्ता ने बार-बार डेटा दर्ज किया और रीसेट बटन दबाया तो मेमोरी लीक नहीं होगी? मैं यह भी सोच रहा था, चूंकि जावा एक भाषा के रूप में काफी परिपक्व है, इसलिए इसे रोकने या इससे निपटने से रोकने के लिए एक तरीका होना चाहिए।


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

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

एक सवाल था जिसने हाल ही में अंतिम रूप देने की गहन चर्चा की , जिससे आवश्यक होने पर अधिक गहराई प्रदान की जानी चाहिए ...


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



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

... ओपी वास्तव में उन सभी चीजों को रखने के लिए एक स्पष्ट स्पष्ट समाधान नहीं होगा जो "playpen" के प्रकार में रीसेट करने की आवश्यकता है, जिसके लिए अन्य सभी गैर-resetable ऑब्जेक्ट्स केवल कुछ प्रकार के संदर्भ हैं एक्सेसर ऑब्जेक्ट का ...

और फिर जब आपको "रीसेट" करने की आवश्यकता होती है तो आप मौजूदा प्लेपेन को डिस्कनेक्ट करते हैं और एक नया बनाते हैं: प्लेपेन में ऑब्जेक्ट्स के सभी वेब को एड्रिफ्ट डाला जाता है, वापस नहीं लौटाया जाता है, और एक दिन जीसी द्वारा एकत्र किया जाता है।

यदि इनमें से कोई भी वस्तु close करने Closeable (या नहीं, लेकिन एक close विधि है) तो आप उन्हें Closeable में एक Bag में डाल सकते हैं क्योंकि उन्हें बनाया गया है (और संभवतः खोला गया है), और playpen को काटने से पहले एक्सेसर का अंतिम कार्य होगा उन्हें बंद करने के सभी बंद करने के माध्यम से जाना होगा ...?

कोड शायद इस तरह कुछ दिखता है:

accessor.getPlaypen().closeCloseables();
accessor.setPlaypen( new Playpen() );

closeCloseables संभवतया एक अवरुद्ध विधि होगी, संभवतया Runnables थ्रेड में Playpen लिए विशिष्ट किसी भी थ्रेड में किसी भी Runnables / Callables से निपटने के लिए (और के लिए उपयुक्त के रूप में प्रतीक्षा करें) ।


मुझे खेद है कि यह मुख्य विषय से निकलता है, लेकिन java.util.Timer (SE6) प्रलेखन कहता है:

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

मैं टाइमर को अपना अंतिम संदर्भ खोने वाले वर्ग पर रद्द करना चाहता हूं (या पहले immeditalesky)। यहां एक विश्वसनीय विनाशक मेरे लिए ऐसा कर सकता है। उपर्युक्त टिप्पणियां इंगित करती हैं कि अंत में एक खराब विकल्प है, लेकिन क्या कोई सुरुचिपूर्ण समाधान है? "... को समाप्त करने से आवेदन रखने में सक्षम ..." का वह व्यवसाय आकर्षक नहीं है।


मैं ज्यादातर उत्तरों से सहमत हूं।

आपको finalize या ShutdownHook पर पूरी तरह निर्भर नहीं होना चाहिए

finalize

  1. जब यह finalize() विधि लागू की जाएगी तो JVM गारंटी नहीं देता है।

  2. finalize() को जीसी थ्रेड द्वारा केवल एक बार बुलाया जाता है यदि ऑब्जेक्ट को अंतिम रूप देने से विधि को अंतिम रूप देने से खुद को पुनर्जीवित किया जाता है तो उसे फिर से नहीं कहा जाएगा।

  3. आपके आवेदन में, आपके पास कुछ जीवित वस्तुएं हो सकती हैं, जिन पर कचरा संग्रह कभी नहीं लगाया जाता है।

  4. अंतिम अपवाद द्वारा फेंक दिया गया कोई भी अपवाद जीसी धागे द्वारा अनदेखा किया जाता है

  5. System.runFinalization(true) और Runtime.getRuntime().runFinalization(true) विधियों को finalize() विधि का आविष्कार करने की संभावना में वृद्धि होती है लेकिन अब इन दो विधियों को बहिष्कृत कर दिया गया है। थ्रेड सुरक्षा और संभावित डेडलॉक निर्माण की कमी के कारण ये विधियां बहुत खतरनाक हैं।

shutdownHooks

public void addShutdownHook(Thread hook)

रजिस्टर्स एक नया आभासी मशीन शट डाउन हुक।

जावा वर्चुअल मशीन दो प्रकार की घटनाओं के जवाब में बंद हो जाती है:

  1. कार्यक्रम सामान्य रूप से बाहर निकलता है, जब अंतिम गैर-डिमन थ्रेड निकलता है या जब बाहर निकलें (समतुल्य, System.exit) विधि लागू की जाती है, या
  2. वर्चुअल मशीन को उपयोगकर्ता इंटरप्ट के जवाब में समाप्त कर दिया जाता है, जैसे कि टाइपिंग सी, या सिस्टम-वाइड इवेंट, जैसे उपयोगकर्ता लॉगऑफ या सिस्टम शट डाउन।
  3. शटडाउन हुक बस एक प्रारंभिक लेकिन अनस्टार्ट थ्रेड है। जब आभासी मशीन अपने शट डाउन अनुक्रम शुरू करती है तो यह कुछ निर्दिष्ट शटडाउन हुक को कुछ अनिर्दिष्ट क्रम में शुरू कर देगी और उन्हें एक साथ चलने देगी। जब सभी हुक समाप्त हो जाते हैं तो यह अंतिम रूप से बाहर निकलने पर सक्षम होने पर सभी अनजान फाइनलरों को चलाएगा।
  4. अंत में, वर्चुअल मशीन रुक जाएगी। ध्यान दें कि शट डाउन अनुक्रम के दौरान डिमन थ्रेड चलते रहेंगे, जैसे बाहर निकलने के तरीके को बंद करके शटडाउन शुरू होने पर गैर-डिमन थ्रेड होंगे।
  5. शटडाउन हुक को भी अपना काम जल्दी खत्म करना चाहिए। जब कोई प्रोग्राम बाहर निकलने का आह्वान करता है तो उम्मीद है कि वर्चुअल मशीन तुरंत बंद हो जाएगी और बाहर निकल जाएगी।

    लेकिन यहां तक ​​कि ओरेकल दस्तावेज ने उद्धृत किया

दुर्लभ परिस्थितियों में वर्चुअल मशीन निरस्त हो सकती है, यानी, साफ-सफाई बंद किए बिना चलना बंद करें

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

निष्कर्ष : try{} catch{} finally{} ब्लॉक को उचित रूप से प्रयास करें और finally(} में महत्वपूर्ण संसाधनों को जारी करें finally(} ब्लॉक। finally{} ब्लॉक में संसाधनों की रिहाई के दौरान, Exception और Throwable


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

उदाहरण:

public myDestructor() {

variableA = 0; //INT
variableB = 0.0; //DOUBLE & FLOAT
variableC = "NO NAME ENTERED"; //TEXT & STRING
variableD = false; //BOOL

}

आदर्श रूप से यह सभी परिस्थितियों के लिए काम नहीं करेगा, लेकिन जहां वैश्विक चर हैं, तब तक यह तब तक काम करेगा जब तक आपके पास उनमें से कोई टन नहीं है।

मुझे पता है कि मैं सबसे अच्छा जावा प्रोग्रामर नहीं हूं, लेकिन ऐसा लगता है कि यह मेरे लिए काम कर रहा है।


यदि आप जावा ऐप्पल लिख रहे हैं, तो आप एप्लेट "नष्ट ()" विधि को ओवरराइड कर सकते हैं। यह है...

 * Called by the browser or applet viewer to inform
 * this applet that it is being reclaimed and that it should destroy
 * any resources that it has allocated. The stop() method
 * will always be called before destroy().

जाहिर है कि आप क्या चाहते हैं, लेकिन हो सकता है कि अन्य लोग क्या ढूंढ रहे हों।


लंबोक में एक @Cleanup एनोटेशन है जो ज्यादातर सी ++ @Cleanup जैसा दिखता है:

@Cleanup
ResourceClass resource = new ResourceClass();

इसे संसाधित करते समय (संकलन समय पर), लंबोक उचित try-finally ब्लॉक को सम्मिलित करता है ताकि resource.close() को लागू किया जा सके, जब निष्पादन चर के दायरे को छोड़ देता है। संसाधन को जारी करने के लिए आप स्पष्ट रूप से एक अन्य विधि भी निर्दिष्ट कर सकते हैं, उदाहरण के लिए resource.dispose() :

@Cleanup("dispose")
ResourceClass resource = new ResourceClass();

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

Java.lang.ref.PhantomReference (वास्तव में, कह रहा है कि इसे नष्ट कर दिया गया है, का उपयोग करके किसी ऑब्जेक्ट को नष्ट कर दिया गया है, इसके बाद आपको अधिसूचित किया जा सकता है, लेकिन यदि इसका एक प्रेत संदर्भ कतारबद्ध है तो यह अब वसूली योग्य नहीं है, जो आमतौर पर वही चीज़)। एक आम उपयोग है:

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

अंतिम रूप दिया जाता है (), जो एक विनाशक की तरह दिखता है लेकिन एक जैसा व्यवहार नहीं करता है। यह आमतौर पर एक अच्छा विकल्प नहीं है।


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

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


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

यदि आपको अपनी ऑब्जेक्ट में डीलोकेशन कॉल की आवश्यकता है, तो संसाधनों को छोड़ने के लिए कहें, एक स्पष्ट विधि कॉल का उपयोग करें। यह सम्मेलन मौजूदा एपीआई में देखा जा सकता है (उदाहरण के लिए बंद करने Closeable , Graphics.dispose() , Widget.dispose() ) और आमतौर पर कोशिश / अंत के माध्यम से बुलाया जाता है।

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

एक डिस्पोजेड ऑब्जेक्ट का उपयोग करने के प्रयासों को रनटाइम अपवाद फेंकना चाहिए ( IllegalStateException देखें)।

संपादित करें:

मैं सोच रहा था, अगर मैंने जो कुछ किया है, वह सिर्फ डेटा को कम करने और कचरा कलेक्टर को इकट्ठा करने का इंतजार कर रहा था, तो क्या मेरे उपयोगकर्ता ने बार-बार डेटा दर्ज किया और रीसेट बटन दबाया तो मेमोरी लीक नहीं होगी?

आम तौर पर, आपको केवल वस्तुओं को कम करना है - कम से कम, यह वही तरीका है जिस पर इसे काम करना है। यदि आप कचरा संग्रहण के बारे में चिंतित हैं, तो जावा एसई 6 हॉटस्पॉट [टीएम] वर्चुअल मशीन कचरा संग्रह ट्यूनिंग (या अपने जेवीएम संस्करण के लिए समकक्ष दस्तावेज़) देखें।





destructor