क्या जावा के लिए एक विनाशकारी है?


594

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

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

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

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


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

17
यदि आप तेजी से ऑब्जेक्ट्स के माध्यम से डेटा प्रोसेसिंग कर रहे हैं तो वर्चुअल मशीन GC को जल्द नहीं चलाएगी। यह विचार कि जीसी हमेशा बना रह सकता है, या सही निर्णय ले सकता है।
कीवेली

1
@ Kieveli कोई त्रुटि देने से पहले JVM GC नहीं चलाएगा?
WVrock

4
हाँ, यह अच्छा होगा यदि जावा के लिए विनाशकारी था जो इसे सभी के लिए एक बार नष्ट कर देगा।
टॉम ज़ातो - मोनिका

जवाबों:


526

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

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

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


5
क्या इस संदर्भ में "बंद ()" java.lang.Autocloseable में विधि को संदर्भित करता है?
श्रीधर सरनोबत

21
नहीं, AutoCloseable को Java 7 में पेश किया गया था, लेकिन 'करीब ()' कन्वेंशन लगभग लंबा रहा है।
जॉन ऑनस्टॉट

जब आप किसी वस्तु को नष्ट किया जाएगा, तब आप इसकी भविष्यवाणी क्यों नहीं कर सकते। अनुमानित करने का अन्य तरीका क्या है?
dctremblay

@dctremblay ऑब्जेक्ट का विनाश कचरा संग्राहक द्वारा किया जाता है और कचरा कलेक्टर कभी भी जीवन भर नहीं चल सकता है।
पीरो का कहना है कि

4
ध्यान दें कि finalizeविधि को जावा 9. में
चित्रित

124

संसाधनों के साथ कथन पर एक नज़र डालें । उदाहरण के लिए:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

यहां जिस संसाधन की अब आवश्यकता नहीं है उसे BufferedReader.close()विधि में मुक्त किया जाता है। आप अपनी खुद की कक्षा बना सकते हैं जो AutoCloseableइसे लागू करती है और इसी तरह से उपयोग करती है।

यह कथन finalizeकोड संरचना की तुलना में अधिक सीमित है , लेकिन साथ ही यह कोड को समझने और बनाए रखने के लिए सरल बनाता है। इसके अलावा, इस बात की कोई गारंटी नहीं है कि finalizeआवेदन के लाइव होने के दौरान एक विधि को कॉल किया जाता है।


12
मुझे आश्चर्य है कि इसमें इतने कम वोट हैं। यह वास्तविक उत्तर है।
नुरेटिन

20
मैं असहमत हूं कि यह वास्तविक जवाब है। यदि किसी इंस्टेंस में एक ऐसा संसाधन होता है, जो समय-समय पर एक से अधिक तरीकों से हैंडल होता है, तो कई तरीकों से कॉल करने में मदद मिलेगी। जब तक इसे बंद करना और फिर से खोलना ठीक नहीं है, तब तक कहा जा सकता है कि दर में संसाधन सामान्य रूप से नहीं - कहा जाता है।
एरिक

14
दरअसल, यह है नहीं वास्तविक जवाब। किसी वस्तु के विनाश का प्रबंधन करने के लिए इस संरचना का उपयोग करना असंभव है जब तक कि वस्तु का निर्माण और उपयोग पूरी तरह से एन्कैप्सुलेटेड न हो tryऔर finallyइसका उपयोग कॉल को बाध्य करने के लिए किया जाता है obj.finalize()। और यहां तक ​​कि यह सेटअप ओपी द्वारा पेश की गई समस्या को हल नहीं करता है: ऑब्जेक्ट विनाश मध्य-कार्यक्रम "रीसेट" बटन द्वारा ट्रिगर किया गया।
7yl4r

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

1
@nurettin Java 7 को केवल 3 महीने के लिए बाहर रखा गया था जब सवाल पूछा गया था, अगर इससे अधिक समझ में आता है।
corsiKa

110

नहीं, यहां कोई विध्वंसक नहीं। कारण यह है कि सभी जावा ऑब्जेक्ट्स को आवंटित और कचरा एकत्र किया जाता है। बिना स्पष्ट सौदे के (यानी C ++ के डिलीट ऑपरेटर) वास्तविक विध्वंसक को लागू करने का कोई समझदार तरीका नहीं है।

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

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


4
देशी संसाधनों का उल्लेख करने के लिए धन्यवाद - यह एक ऐसा क्षेत्र है जहां "विध्वंसक-जैसी" विधि उपयोगी है।
नाथन उस्मान

हां, मैं अभी उसी समस्या का सामना कर रहा हूं, जिसमें C ++ के लिए देशी कॉल के माध्यम से आवंटित संसाधनों / हैंडल को मुक्त करना है।
nikk

@ddimitrov, सिद्धांत रूप में जावा स्पष्ट व्यवहार को लागू कर सकता है? या यह एक तार्किक विरोधाभास है?
मील

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

31

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

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

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

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


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

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

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


1
यही कारण नहीं है कि dereference। यह "किसी ऑब्जेक्ट के अंतिम संदर्भ को अशक्त करने के लिए सेट नहीं है" बल्कि संदर्भ से मूल्य प्राप्त करना (पढ़ना) है ताकि आप इसे बाद के कार्यों के लिए उपयोग कर सकें।

1
क्या प्रयास..यदि अभी भी एक मान्य और अनुशंसित दृष्टिकोण है? मान लीजिए, मैं पहले अंतिम रूप में एक देशी विधि कह रहा था (), क्या मैं कॉल को अंतिम रूप से बंद कर सकता हूं? class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
आशिमा

r अंत में ब्लॉक करने के लिए scoped नहीं किया जाएगा। इसलिए, आप उस बिंदु पर विनाश को कॉल नहीं कर सकते। अब, यदि आप प्रयास ब्लॉक से पहले ऑब्जेक्ट निर्माण के दायरे को सही करते हैं, तो आप "कोशिश-के-संसाधनों से पहले" मामले के साथ बदसूरत हो जाएंगे।
userAsh

21

जावा 1.7 जारी होने के साथ, अब आपके पास try-with-resourcesब्लॉक का उपयोग करने का अतिरिक्त विकल्प है । उदाहरण के लिए,

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing..."); 
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying..."); 
            throw new Exception("throwing..."); 
        }
        catch (Exception e) {
            System.out.println("catching..."); 
        }
        finally {
            System.out.println("finalizing..."); 
        } 
    }
}

यदि आप इस वर्ग c.close()को निष्पादित करते हैं, तो tryब्लॉक के बचे रहने पर निष्पादित किया जाएगा , और इससे पहले catchऔर finallyब्लॉक निष्पादित किए जाते हैं। finalize()विधि के मामले में विपरीत , close()निष्पादित होने की गारंटी है। हालांकि, finallyक्लॉज में इसे स्पष्ट रूप से निष्पादित करने की आवश्यकता नहीं है ।


क्या होगा अगर हमने संसाधन ब्लॉक के साथ प्रयास नहीं किया है? मुझे लगता है कि हम अंतिम रूप में बंद कर सकते हैं () यह सुनिश्चित करने के लिए कि करीबी को बुलाया गया है।
शिंत्ज़ो

3
@ शिन्तोज़ जैसा कि मैंने उपरोक्त उत्तरों में पढ़ा है कि finalize()निष्पादन की कोई गारंटी नहीं है
आसिफ मुश्ताक

14

मैं अन्य उत्तरों से पूरी तरह सहमत हूं, अंतिम रूप देने पर भरोसा करने के लिए नहीं।

ट्राइ -कैच-आखिर ब्लॉक के अलावा, आप अपने प्रोग्राम में अंतिम क्लीनअप करने के लिए रनटाइम # addShutdownHook (जावा 1.3 में पेश) का उपयोग कर सकते हैं ।

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

इस का लाभ विखंडन व्यवहार कर रहा है शिथिल युग्मित अपने कार्यक्रम के बाकी हिस्सों से।


addShutdownHook को जाहिरा तौर पर Java 1.3 में पेश किया गया था। वैसे भी, यह मेरे लिए 1.5 में उपलब्ध है। :) इसे देखें: stackoverflow.com/questions/727151/…
Skiphoppy

1
FYI करें, मेरे अनुभव में शटडाउन हुक को नहीं बुलाया जाएगा यदि आप ग्रहण में लाल "टर्मिनेट" बटन का उपयोग करते हैं - पूरे जेवीएम को तुरंत नष्ट कर दिया जाता है, शटडाउन हुक को इनायत से नहीं कहा जाता है। मतलब अगर आप ग्रहण के दौरान विकसित होते हैं तो आप विकास और उत्पादन के दौरान अलग-अलग व्यवहार देख सकते हैं
Hamy

11

नहीं, java.lang.Object#finalizeनिकटतम आप प्राप्त कर सकते हैं।

हालांकि, जब (और यदि) इसे कहा जाता है, तो गारंटी नहीं है।
देख:java.lang.Runtime#runFinalizersOnExit(boolean)


5
एक विधि जिसे बुलाया जा सकता है या नहीं वह अनिवार्य रूप से मेरी पुस्तक में बेकार है। बेहतर होगा कि भाषा को बेकार विशेष पद्धति से प्रदूषित न किया जाए, जो कि सुरक्षा का झूठा एहसास देता है। मैं कभी नहीं समझ पाऊंगा कि जावा भाषा के डेवलपर्स ने अंतिम रूप से सोचा कि यह एक अच्छा विचार क्यों था।
विरोध किया

@antred जावा भाषा के डेवलपर्स सहमत हैं । मुझे लगता है, वापस, उनमें से कुछ के लिए, यह पहली बार था जब उन्होंने कचरा संग्रह के साथ एक प्रोग्रामिंग भाषा और रनटाइम वातावरण तैयार किया था। क्या कम समझ में आता है, यही कारण है कि अन्य प्रबंधित भाषा ने उस अवधारणा को एक समय में कॉपी किया , जब यह पहले से ही समझा गया था कि यह अवधारणा एक बुरा विचार है।
होल्गर

7

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

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

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

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


क्यों एक WeakReference के बजाय एक प्रेत बाधा?
ऑकेलमैन

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

PhantomReference पर संकेत देने के लिए धन्यवाद। यह सही नहीं है, लेकिन अभी भी कुछ भी नहीं से बेहतर है।
फू

@SteveJessop क्या "अतिरिक्त काम", क्या आपको लगता है, एक प्रेत संदर्भ की तुलना में कमजोर संदर्भ है?
होल्गर

6

finalize()समारोह नाशक है।

हालाँकि, इसका सामान्य रूप से उपयोग नहीं किया जाना चाहिए क्योंकि यह GC के बाद लगाया जाता है और आप यह नहीं बता सकते कि ऐसा कब होगा (यदि कभी हो)।

इसके अलावा, यह एक से अधिक GC लेता है जो वस्तुओं को हटाने के लिए है finalize()

आपको try{...} finally{...}बयानों का उपयोग करके अपने कोड में तार्किक स्थानों को साफ करने की कोशिश करनी चाहिए !


5

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

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

को अंतिम रूप देने

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

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

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

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

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

shutdownHooks

public void addShutdownHook(Thread hook)

एक नया वर्चुअल-मशीन शटडाउन हुक पंजीकृत करता है।

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

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

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

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

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

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


4

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


3

शायद आप एक कोशिश का उपयोग कर सकते हैं ... अंत में नियंत्रण प्रवाह में उस वस्तु को अंतिम रूप देने के लिए जिस पर आप ऑब्जेक्ट का उपयोग कर रहे हैं। बेशक यह स्वचालित रूप से नहीं होता है, लेकिन न तो सी ++ में विनाश होता है। आप अक्सर अंत में ब्लॉक में संसाधनों को बंद करते हुए देखते हैं।


1
यह सही उत्तर है जब प्रश्न में संसाधन के पास एक एकल स्वामी होता है और उसके पास कभी भी अन्य कोड द्वारा "चोरी" के संदर्भ नहीं होते हैं।
स्टीव जेसप

3

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

@Cleanup
ResourceClass resource = new ResourceClass();

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

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

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

एक कोशिश के साथ संसाधन ब्लॉक में एक शॉट में कई संसाधन हो सकते हैं
अलेक्जेंडर - बहाल मोनिका

1
लेकिन इसमें उनके बीच निर्देश नहीं हो सकते।
एलेक्सी

मेला। मुझे लगता है कि सिफारिश कई संसाधनों के लिए, यहां तक ​​कि कई संसाधनों के लिए भी कोशिश करना है, जब तक कि उन दोनों के बीच निर्देश होने की आवश्यकता न हो जो आपको नए प्रयास-संसाधन ब्लॉक (बढ़ते घोंसले) बनाने के लिए मजबूर करते हैं, तो उपयोग करें@Cleanup
अलेक्जेंडर - बहाल करें मोनिका

2

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


2

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

यदि JVM के कारण बाहर निकलता है System.exit()या Runtime.getRuntime().exit(), अंतिम रूप से डिफ़ॉल्ट रूप से नहीं चलाया जाएगा। Runtime.exit के लिए Javadoc से () :

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

आप कॉल कर सकते हैं System.runFinalization()लेकिन यह केवल "सभी बकाया फाइनल को पूरा करने का सबसे अच्छा प्रयास करता है" - गारंटी नहीं।

एक System.runFinalizersOnExit()विधि है, लेकिन इसका उपयोग न करें - यह असुरक्षित है, बहुत पहले ही हटा दिया गया था।


1

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

 * 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().

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


1

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

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

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

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

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

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

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


0

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

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


0

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

को अंतिम रूप देने ()

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


0

किसी भी जावा के पास कोई विध्वंसक नहीं है। जावा में इसके पीछे मुख्य कारण कचरा संग्राहक हैं जो हमेशा पृष्ठभूमि में काम करते हैं और सभी ऑब्जेक्ट्स ढेर मेमोरी में बने होते हैं, यही वह जगह है जहां जीसी काम करता है। c ++ में हम। हटाए गए फ़ंक्शन को स्पष्ट रूप से कॉल करना होगा क्योंकि कोई कचरा संग्रहकर्ता जैसी चीज़ नहीं है।


-3

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

उदाहरण:

public myDestructor() {

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

}

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

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


अपरिवर्तनीय वस्तुओं का अधिक उपयोग करने का प्रयास करें, आपके द्वारा इसे प्राप्त करने के बाद यह सब और अधिक समझ में आ जाएगा :)
R. van Twisk

5
यह इतना गलत नहीं है क्योंकि यह व्यर्थ है - यानी कुछ भी हासिल नहीं करता है। यदि आपके प्रोग्राम को सही ढंग से काम करने के लिए कच्चे प्रकार को रीसेट करने की आवश्यकता है, तो आपकी कक्षाएं उदाहरण गलत तरीके से बंद कर दी गई हैं, जिसका अर्थ है कि आप एक नई वस्तु के गुणों के बिना एक मौजूदा वस्तु के गुणों को पुन: सौंप रहे हैं।
simo.3792

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