2012-01-11 18 views
12

में ऑब्जेक्ट्स लाइफेंस मैं "सी # के माध्यम से सीएलआर" पढ़ रहा था और ऐसा लगता है कि इस उदाहरण में, ऑब्जेक्ट जिसे 'ओबीजे' को सौंपा गया था, लाइन 1 के बाद कचरा संग्रह के लिए पात्र होगा, बाद में नहीं लाइन 2.जावा बनाम .NET

void Foo() 
{ 
    Object obj = new Object(); 
    obj = null; 
} 

क्योंकि स्थानीय चर उम्र गुंजाइश है जिसमें यह परिभाषित किया गया था द्वारा नहीं परिभाषित है यही कारण है, लेकिन पिछली बार से आप इसे पढ़ सकते हैं।

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

class TestProgram { 

    public static void main(String[] args) { 
     TestProgram ref = new TestProgram(); 
     System.gc(); 
    } 

    @Override 
    protected void finalize() { 
     System.out.println("finalized"); 
    } 
} 

जोड़ा गया: जेफरी रिक्टर "सी # के माध्यम से CLR" में कोड उदाहरण देता है, कुछ इस तरह:

public static void Main (string[] args) 
{ 
    var timer = new Timer(TimerCallback, null, 0, 1000); // call every second 
    Console.ReadLine(); 
} 

public static void TimerCallback(Object o) 
{ 
    Console.WriteLine("Callback!"); 
    GC.Collect(); 
} 

TimerCallback एमएस नेट पर केवल एक बार कहा जाता है, तो परियोजनाओं लक्ष्य है 'रिलीज' (घड़ी जीसी। कोलेक्ट() कॉल के बाद नष्ट कर दिया गया है, और यदि लक्ष्य 'डीबग' है तो प्रत्येक सेकेंड को बुलाया जाता है (वेरिएबल जीवनकाल बढ़ता है क्योंकि प्रोग्रामर डीबगर के साथ ऑब्जेक्ट तक पहुंचने का प्रयास कर सकता है)। लेकिन मोनो कॉलबैक पर हर सेकेंड कहा जाता है इससे कोई फर्क नहीं पड़ता कि आप इसे कैसे संकलित करते हैं। ऐसा लगता है कि मोनो के 'टाइमर' कार्यान्वयन स्टोर थ्रेड पूल में कहीं उदाहरण के संदर्भ में हैं। एमएस कार्यान्वयन ऐसा नहीं करता है।

+10

मैं जावा स्पेक में इसे खोजने में विफल रहा हूं। ध्यान दें कि .NET आपके अपेक्षा की तुलना में भी पागल हो सकता है - उदाहरण के लिए एक उदाहरण विधि को निष्पादित किया जा सकता है * जबकि सीएलआर जानता है कि कोई और आवृत्ति चर निर्दिष्ट नहीं किया जाएगा। –

उत्तर

4

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

गम्यता/collectability के विषय पर, JLS कहते हैं (12.6.1):

एक पहुंच योग्य वस्तु किसी भी वस्तु है कि किसी भी लाइव धागे से किसी भी संभावित जारी गणना में पहुँचा जा सकता है है। किसी प्रोग्राम के रूपांतरणों को अनुकूलित करने के लिए डिज़ाइन किया जा सकता है जो उन वस्तुओं की संख्या को कम करता है जो उन लोगों से कम होने के लिए पहुंच योग्य हैं जिन्हें बेवकूफ़ माना जा सकता है। उदाहरण के लिए, एक कंपाइलर या कोड जेनरेटर एक वेरिएबल या पैरामीटर सेट करने का विकल्प चुन सकता है जिसे अब इस ऑब्जेक्ट के लिए भंडारण को संभावित रूप से पुनः प्राप्त करने के लिए उपयोग करने के लिए उपयोग नहीं किया जाएगा।

कौन सा कम या ज्यादा क्या आप वास्तव में क्या उम्मीद थी है - मुझे लगता है कि उपरोक्त अनुच्छेद के साथ "एक वस्तु निश्चित रूप से आप iff पहुंच योग्य नहीं है यह किसी भी अधिक का उपयोग नहीं होगा" isomorphic है।

अपनी मूल स्थिति पर वापस जाएं, क्या आप लाइन 2 के विपरीत लाइन 1 के बाद पहुंचने योग्य ऑब्जेक्ट के बीच किसी भी व्यावहारिक विध्वंस के बारे में सोच सकते हैं? मेरी प्रारंभिक प्रतिक्रिया यह है कि कोई भी नहीं है, और यदि आप किसी भी तरह की स्थिति ढूंढने में कामयाब रहे हैं तो यह संभवतः खराब/मुड़ वाले कोड का निशान होगा जिससे वीएम भाषा में अंतर्निहित कमजोरी के बजाय संघर्ष कर सकता है।

हालांकि मैं काउंटर-तर्कों के लिए खुला हूं।


संपादित करें: दिलचस्प उदाहरण के लिए धन्यवाद।

मैं आपके मूल्यांकन से सहमत हूं और देख रहा हूं कि आप कहां जा रहे हैं, हालांकि समस्या शायद अधिक है कि डीबग मोड आपके कोड के अर्थशास्त्र को संक्षेप में बदल रहा है।

लिखित कोड में, आप Timer को एक स्थानीय चर में निर्दिष्ट करते हैं जिसे बाद में इसके दायरे में नहीं पढ़ा जाता है। यहां तक ​​कि सबसे तुच्छ बचने का विश्लेषण भी प्रकट कर सकता है कि timer चर का उपयोग main विधि में कहीं और नहीं किया जाता है, और इसलिए इसे बढ़ाया जा सकता है। इसलिए मुझे लगता है कि अपनी पहली लाइन वास्तव में सिर्फ सीधे निर्माता लागू के समकक्ष माना जा सकता है:

public static void Main (string[] args) 
{ 
    new Timer(TimerCallback, null, 0, 1000); // call every second 
    ... 

बाद वाले मामले में यह स्पष्ट है कि नव निर्मित Timer वस्तु तुरंत निर्माण के बाद (यह सोचते हैं कि ऐसा नहीं 'पहुंच योग्य नहीं है अपने कन्स्ट्रक्टर में स्थिर फ़ील्ड इत्यादि जैसे खुद को जोड़ने की तरह कुछ भी चुपके नहीं करते हैं); और जैसे ही जीसी इसके चारों ओर घूमता है, इसे इकट्ठा किया जाएगा।

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

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

पर इस बिंदु पर मैं आपको इस जवाब में पहली वाक्य पर वापस भेजता हूं। :)

+0

उत्तर के लिए धन्यवाद। मैं अपना प्रश्न संपादित करूंगा और वहां कोड उदाहरण जोड़ूंगा। – Ivan

+1

मैंने अपनी पोस्ट में कोड उदाहरण जोड़ा है, यह विभिन्न कार्यान्वयन पर विभिन्न प्रोग्राम व्यवहार दिखाता है।उस अनुकूलन के कारण नेट और विभिन्न निर्माण लक्ष्य के साथ। – Ivan

+0

अंडरलेइंग वातावरण में परिवर्तनीय जीवनकाल = = भाषा में से एक के लिए, इमो ऐसा व्यवहार अनजान है और सिद्धांत में कोड तोड़ सकता है, हालांकि मुझे नहीं लगता कि यह वास्तव में एक समस्या है। बस सोच रहा है कि क्या जावा चश्मा ऐसे मामलों के बारे में कुछ कहता है। जीसी का उपयोग हर दिन अधिक से अधिक जटिल लग रहा है :) – Ivan

1

जावा, सामान्य रूप से, व्यवहार में यह व्यवहार होता है कि यदि वस्तु दायरे में पहुंच योग्य है (इसका संदर्भ है जो कचरा नहीं है), तो वस्तु कचरा नहीं है। यह रिकर्सिव है, इसलिए यदि a किसी ऑब्जेक्ट का संदर्भ है जिसमें b का संदर्भ है, तो ऑब्जेक्ट b का मतलब कचरा नहीं है।

गुंजाइश जहां आप अभी भी वस्तु ref द्वारा संदर्भित तक पहुँच सकते हैं के भीतर,, (यदि आप एक लाइन System.out.println(ref.toString()) जोड़ सकता है) ref कचरा नहीं है।

हालांकि, this old source from Sun's site के अनुसार, अधिकांश JVM के विशिष्ट कार्यान्वयन पर निर्भर करता है।

संबंधित मुद्दे