2013-08-04 7 views
12

को अंतिम रूप देने के लिए क्या finalizer धागा अगर वहाँ एक अनंत लूप करते हैं या जावा में गतिरोध जाएगा विधि को अंतिम रूप देने।अगर वहाँ एक अनंत लूप या जावा में गतिरोध है finalizer धागा क्या करेंगे विधि

+4

क्या आप इसे आजमाते हुए किसी भी व्यवहार को साझा कर सकते हैं? –

+0

यह देखना मुश्किल है, जेवीएम यह भी गारंटी नहीं देता है कि 'अंतिमकरण' कहा जाएगा, सुइयों को यह कहने के लिए कहा जाता है कि आपको यह नहीं पता कि यह कहां जा रहा है – morgano

+0

@ मॉर्गनो एक सरल 'println' पर्याप्त है। मैंने बहुत समय पहले इस के साथ खेला है, 'अंतिम रूप' को तत्काल बुलाया जा रहा है। केवल दुर्लभ मामले हैं जब कुछ अप्राप्य वस्तुओं को सिस्टम शटडाउन तक अंतिम रूप दिया नहीं जाता है। –

उत्तर

13

कल्पना लिखते हैं:

से पहले एक वस्तु के लिए भंडारण कचरा कलेक्टर द्वारा पुन: दावा किया जाता है, जावा वर्चुअल मशीन उस वस्तु की finalizer आह्वान करेंगे।

जावा प्रोग्रामिंग भाषा निर्दिष्ट नहीं करती है कि फाइनलर कितनी जल्दी लागू किया जाएगा, यह कहकर कि ऑब्जेक्ट के भंडारण का पुन: उपयोग करने से पहले यह होगा।

मैंने इसका अर्थ यह है कि भंडारण का पुन: उपयोग करने से पहले अंतिमकर्ता को पूरा करना होगा।

जावा प्रोग्रामिंग भाषा निर्दिष्ट नहीं करती है कि कौन सा थ्रेड किसी दिए गए ऑब्जेक्ट के लिए फ़ाइनलज़र का आह्वान करेगा।

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

यही है, कचरा कलेक्टर थ्रेड में एक अलग थैड में, या यहां तक ​​कि एक अलग थ्रेड पूल में अंतिम रूप हो सकता है।

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

public class Test { 

    byte[] memoryHog = new byte[1024 * 1024]; 

    @Override 
    protected void finalize() throws Throwable { 
     System.out.println("Finalizing " + this + " in thread " + Thread.currentThread()); 
     for (;;); 
    } 

    public static void main(String[] args) { 
     for (int i = 0; i < 1000; i++) { 
      new Test(); 
     } 
    } 
} 

ओरेकल JDK 7 पर, यह प्रिंट:

निम्नलिखित परीक्षण कार्यक्रम इस व्यवहार की पुष्टि करता है

Finalizing [email protected] in thread Thread[Finalizer,8,system] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
     at tools.Test.<init>(Test.java:5) 
     at tools.Test.main(Test.java:15) 
+1

+1, एक ही परीक्षण किया था, और एक ही परिणाम मिला। केवल एक फाइनलाइज़र धागा शामिल है। –

+0

@mriton, ** _ का अर्थ क्या है यह ध्यान रखना महत्वपूर्ण है कि कई फ़ाइनलाइज़र थ्रेड सक्रिय हो सकते हैं (इसे कभी-कभी बड़े साझा स्मृति मल्टीप्रोसेसरों पर आवश्यक होता है) _ **। क्या हमारे पास सीसीएस जैसे जीसी एल्गोरिदम के साथ कोई संबंध है। और, फाइनलाइज़र थ्रेड और जीसी एल्गोरिदम की संख्या के बीच एक रिश्ता है। – andy

+1

एक JVM ऐसा कर सकता है हालांकि यह चाहता है, और विभिन्न JVMs इसे अलग-अलग कर सकते हैं। यदि आप किसी विशेष JVM में रूचि रखते हैं, तो इसके दस्तावेज़ (या अधिक संभावना, इसका स्रोत कोड) देखें। lpiepiora का एवर इंगित करता है कि उपयोग में कचरा संग्रह एल्गोरिदम के बावजूद ओरेकल जेवीएम में हमेशा एक फाइनलज़र थ्रेड होता है। – meriton

4

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

कल्पना चल रही प्रक्रिया को एक से अधिक थ्रेड होने से इनकार नहीं करता, लेकिन यह की आवश्यकता नहीं है:

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

JDK7 के स्रोतों को देखते हुए, FinalizerThread अंतिम रूप दिए जाने के लिए निर्धारित वस्तुओं की कतार रहती है (वास्तव में वस्तुओं जीसी द्वारा कतार में जोड़ा जाता है, जब साबित नहीं पहुंचा जा सकता है - ReferenceQueue डॉक जाँच):

private static class FinalizerThread extends Thread { 
    private volatile boolean running; 
    FinalizerThread(ThreadGroup g) { 
     super(g, "Finalizer"); 
    } 
    public void run() { 
     if (running) 
      return; 
     running = true; 
     for (;;) { 
      try { 
       Finalizer f = (Finalizer)queue.remove(); 
       f.runFinalizer(); 
      } catch (InterruptedException x) { 
       continue; 
      } 
     } 
    } 
} 

प्रत्येक ऑब्जेक्ट कतार से हटा दिया जाता है, और runFinalizer विधि उस पर चलती है। चेक किया जाता है यदि अंतिमकरण ऑब्जेक्ट पर चलाया गया था, और यदि नहीं, तो इसे मूल विधि invokeFinalizeMethod पर कॉल के रूप में बुलाया जा रहा है। विधि बस वस्तु पर finalize विधि बुला रहा है:

JNIEXPORT void JNICALL 
Java_java_lang_ref_Finalizer_invokeFinalizeMethod(JNIEnv *env, jclass clazz, 
                jobject ob) 
{ 
    jclass cls; 
    jmethodID mid; 

    cls = (*env)->GetObjectClass(env, ob); 
    if (cls == NULL) return; 
    mid = (*env)->GetMethodID(env, cls, "finalize", "()V"); 
    if (mid == NULL) return; 
    (*env)->CallVoidMethod(env, ob, mid); 
} 

यह एक ऐसी स्थिति है, जहां वस्तुओं की सूची में पंक्तिबद्ध करने के लिए नेतृत्व चाहिए, जबकि FinalizerThread दोषपूर्ण वस्तु, जो बारी में नेतृत्व करना चाहिए पर अवरुद्ध है OutOfMemoryError पर।

क्या finalizer धागा अगर वहाँ एक अनंत लूप या जावा में गतिरोध को अंतिम रूप देने विधि है क्या करेंगे:

तो मूल सवाल का जवाब देने।

यह बस वहां बैठेगा और उस अनंत लूप को OutOfMemoryError तक चलाएगा।

public class FinalizeLoop { 
    public static void main(String[] args) { 
     Thread thread = new Thread() { 
      @Override 
      public void run() { 
       for (;;) { 
        new FinalizeLoop(); 
       } 
      } 
     }; 
     thread.setDaemon(true); 
     thread.start(); 
     while (true); 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     super.finalize(); 
     System.out.println("Finalize called"); 
     while (true); 

    } 
} 

नोट करें "जेडीके 6 और जेडीके 7 पर केवल एक बार मुद्रित होने पर" अंतिम रूप दिया गया "नोट करें।

+0

क्षमा करें, मैं उपरोक्त आपके उदाहरण कोड से सहमत नहीं हूं। लूप के लिए मुख्य थ्रेड के रूप में एक ही समय में समाप्त हो जाएगा, इसलिए आप ** ** कुछ भी नहीं देख सकते हैं। – andy

+0

@andy आप सही हैं, मैंने यह सुनिश्चित करने के लिए थोड़ा सा कोड बदल दिया है कि आप अंततः कुछ देखेंगे - मुझे लगता है कि जब आपका जीसी अंदर आता है तो धन्यवाद! धन्यवाद! – lpiepiora

0

वस्तुओं को "मुक्त नहीं किया जाएगा", यह स्मृति उनसे वापस नहीं ली जाएगी और अंतिम संसाधन में मुक्त संसाधन भी आरक्षित रहेगा।

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

यदि यह धागा डेडलॉक हो जाएगा तो संदर्भक्यू क्यू बढ़ेगा और किसी बिंदु पर ओओएम त्रुटि अनजान हो जाएगी। इसके अलावा संसाधनों को इस कतार में वस्तुओं द्वारा लगाया जाएगा। उम्मीद है की यह मदद करेगा!!

for(;;) 
{ 
    Finalizer f = java.lang.ref.Finalizer.ReferenceQueue.remove(); 
    f.get().finalize(); 
} 
संबंधित मुद्दे