2011-11-22 14 views
14

में विश्लेषण से बचें क्या सीएलआर कंपाइलर/जेआईटी द्वारा किया गया कोई भी बचाना विश्लेषण है? उदाहरण के लिए, जावा में ऐसा लगता है कि एक लूप वैरिएबल एक लूप में आवंटित ऑब्जेक्ट जो लूप से बचता नहीं है ढेर के बजाय ढेर पर आवंटित किया जाता है (Escape analysis in Java देखें)।.NET CLR VM

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

class Foo 
{ 
    int number; 
    Foo(int number) { this.number = number; } 
    public override string ToString() { return number.ToString(); } 
} 

for (int i = 0; i < 10000000; i++) 
{ 
    Foo foo = new Foo(i); 
    Console.WriteLine(foo.ToString()); 
} 
+0

आमतौर पर प्रकट होता है के शब्दों में परिवर्तन, एक पाश चर एक मूल्य के प्रकार है, जो पर आवंटित हो जाता है ढेर (एक पाश के मामले में)। –

+0

मेरा मतलब लूप बॉडी के भीतर आवंटित एक चर है। मैं स्पष्ट करने के लिए सवाल अपडेट करूंगा। – SimonC

+0

क्या आपका मतलब * चर * है? या * ऑब्जेक्ट *? (अवधारणात्मक रूप से बहुत अलग) –

उत्तर

11

यदि आपका मतलब ऑब्जेक्ट (new Foo(i);) है, तो मेरी समझ यह है कि नहीं: यह कभी भी ढेर पर आवंटित नहीं किया जाता है; हालांकि, यह पीढ़ी शून्य में मर जाएगा, इसलिए इकट्ठा करने के लिए बहुत ही कुशल होगा। मैं सीएलआई के हर अंधेरे और डंक कोने को जानने का दावा नहीं करता हूं, लेकिन मुझे किसी भी परिदृश्य से अवगत नहीं है, जो सी # में है जो स्टैक पर आवंटित एक प्रबंधित संदर्भ-प्रकार का कारण बनता है (stackalloc जैसी चीजें वास्तव में नहीं गिनती, और अत्यधिक विशिष्ट हैं)। जाहिर है सी ++ में आपके पास कुछ और विकल्प हैं, लेकिन फिर यह एक प्रबंधित उदाहरण नहीं है।

दिलचस्प बात यह है कि मोनो टच/एओटी पर तुरंत एकत्र किया जा सकता है, लेकिन यह मुख्य सीएलआई वीएम नहीं है (और यह एक बहुत ही विशिष्ट परिदृश्य के लिए है)।

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

i (पाश चर) के लिए के रूप में - अगर कि पर कब्जा कर लिया जाता है, यह और भी दिलचस्प

  • सी # 1.2 कैप्चर मौजूद नहीं था में हो जाता है, लेकिन कल्पना से पाश-चर है तकनीकी रूप से प्रति-यात्रा
  • में सी # 2.0 4.0 करने के लिए, पाश चर साझा किया जाता है सी # 5.0 में और ऊपर पाश चर प्रति-यात्रा फिर से
  • है
  • (कुख्यात कब्जा/foreach आम सवाल पैदा कर रहा)

यह केवल एक अंतर जब चर कब्जा कर लिया है बनाता है, लेकिन वास्तव में कैसे यह कब्जा संदर्भ

1

जबकि 86 JIT 'इनलाइन किए जाने वाले' valuetypes में अच्छा है, अपने टुकड़ा योग्य नहीं होंगे रूप ToString विधि एक बॉक्स्ड वस्तु पर एक आभासी कॉल किया जाएगा। संपादित करें: यह मामला नहीं हो सकता है, क्योंकि आप ToString ओवरराइड नहीं कर रहे हैं।

x64 जेआईटी हालांकि मेरे प्रयोगों से यह बिल्कुल नहीं करता है।

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

संभव हो तो, दोनों x86 और x64 पर अपने कोड का परीक्षण।

+1

'Foo' हालांकि एक वर्ग है, इसलिए मुझे यकीन नहीं है कि यह कितना लागू होता है। –

5

स्टैक पर हमेशा एक मान प्रकार आवंटित किया जा सकता है (हमेशा नहीं), लेकिन संदर्भ प्रकारों के उदाहरणों के लिए यह भी सच नहीं है। वास्तव में:

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

(एरिक Lippert: The Truth About Value Types)

इसके अलावा The Stack Is An Implementation Detail एक अच्छा पढ़ने में आता है।