WeakRef विधि वस्तु की उम्मीद
के रूप में वहाँ है कि उम्मीद करने का कोई कारण नहीं जमा करता है। लिंकपैड में कोशिश कर रहा है, यह डीबग बिल्ड में नहीं होता है, उदाहरण के लिए, हालांकि डीबग और रिलीज बिल्ड दोनों के अन्य वैध संकलन या तो व्यवहार कर सकते हैं।
कंपाइलर और जिटर के बीच, वे शून्य-असाइनमेंट को ऑप्टिमाइज़ करने के लिए स्वतंत्र हैं (कुछ भी बाद में foo
का उपयोग नहीं करता है), इस मामले में जीसी अभी भी ऑब्जेक्ट का संदर्भ रखने के रूप में थ्रेड को देख सकता है और नहीं इसे इकट्ठा करो। इसके विपरीत, अगर foo = null
का कोई असाइनमेंट नहीं था, तो उन्हें यह एहसास हो जाएगा कि foo
का उपयोग अब और नहीं किया जाता है और स्मृति का पुन: उपयोग या पंजीकरण करने के लिए इसे fooRef
(या वास्तव में किसी और चीज़ के लिए) रखने के लिए पकड़ा गया था foo
।
तो, दोनों के साथ और foo = null
बिना के बाद से इसकी वैधता की जीसी foo
या तो निहित या निहित नहीं के रूप में देखने के लिए, हम यथोचित या तो व्यवहार की अपेक्षा कर सकते हैं।
फिर भी, व्यवहार देखा एक उचित क्या शायद क्या होगा के रूप में उम्मीद है, लेकिन है कि यह गारंटी नहीं है उनका कहना है लायक है।
ठीक है, उस तरफ, चलो देखते हैं कि वास्तव में यहां क्या होता है।
async
विधि द्वारा उत्पादित राज्य-मशीन स्रोत में स्थानीय लोगों के अनुरूप फ़ील्ड के साथ एक संरचना है।
तो कोड:
var foo = new Foo();
WeakReference fooRef = new WeakReference(foo);
foo = null;
GC.Collect();
थोड़ा की तरह है:
this.foo = new Foo();
this.fooRef = new WeakReference(foo);
this.foo = null;
GC.Collect();
लेकिन क्षेत्र हमेशा है कुछ स्थानीय स्तर पर चल रहा एक्सेस करता है।
var temp0 = new Foo();
this.foo = temp0;
var temp1 = new WeakReference(foo);
this.fooRef = temp1;
var temp2 = null;
this.foo = temp2;
GC.Collect();
और temp0
nulled नहीं किया गया है, इसलिए जीसी Foo
के रूप में निहित पाता है: तो इस संबंध में यह लगभग की तरह है।अपने कोड की
दो दिलचस्प वेरिएंट हैं:
var foo = new Foo();
WeakReference fooRef = new WeakReference(foo);
foo = null;
await Task.Delay(0);
GC.Collect();
और:
var foo = new Foo();
WeakReference fooRef = new WeakReference(foo);
foo = null;
await Task.Delay(1);
GC.Collect();
जब मैंने इसे भाग गया (फिर से, कैसे स्मृति/स्थानीय लोगों के लिए रजिस्टर के साथ पेश किया गया है में उचित मतभेद हो सकता है अलग-अलग परिणामों में) पहले आपके उदाहरण का वही व्यवहार होता है, क्योंकि जब यह Task
विधि और await
एस में कॉल करता है, तो यह विधि एक पूर्ण कार्य देता है ताकि await
तुरंत n पर चला जाए एक ही अंतर्निहित विधि कॉल के भीतर ext चीज, जो GC.Collect()
है। क्योंकि उस बिंदु पर await
रिटर्न और उसके बाद राज्य मशीन अपने MoveNext()
विधि मोटे तौर पर एक millisecond बाद में पुन: कहा जाता है
दूसरा, Foo
एकत्र देखने का व्यवहार है। चूंकि यह पीछे के दृश्यों के लिए एक नई कॉल है, इसलिए Foo
का कोई स्थानीय संदर्भ नहीं है, इसलिए जीसी वास्तव में इसे एकत्र कर सकता है।
संयोग से, यह भी संभव है कि एक दिन संकलक उन स्थानीय लोगों के लिए खेतों का उत्पादन नहीं करेगा जो await
सीमाओं में नहीं रहते हैं, जो एक अनुकूलन होगा जो अभी भी सही व्यवहार का उत्पादन करेगा। यदि ऐसा होता है तो आपके दो तरीके अंतर्निहित व्यवहार में बहुत समान हो जाएंगे और इसलिए मनाए गए व्यवहार में समान होने की संभावना है।
मजे की बात है अगर आप कचरा संग्रहण इसे एकत्र हो जाता है का इंतजार है 'का इंतजार System.Threading.Tasks.Task.Run (() => GC.Collect());' – Equalsk
पहले सोचा: शायद क्योंकि 'foo' और' fooRef 'async' विधि में कंपाइलर से उत्पन्न राज्य मशीन वर्ग के गुण बन जाते हैं। लेकिन मैंने इन चरों को किसी अन्य वर्ग में लपेटकर कोशिश की और वे एकत्र हो गए .... क्या जीसी पूछने का कोई तरीका है जहां/अभी भी 'फू' इंस्टेंस का संदर्भ दे रहा है? –
आईएमएचओ, आपकी विधि को कंपाइलर द्वारा कक्षा में अनुवादित किया गया है और संकलक निर्णय लेता है कि 'foo' उस वर्ग का सदस्य है। इसलिए जब तक आपकी विधि का प्रतिनिधित्व करने वाली वस्तु जीवित है, तब भी इसके सदस्य कचरा नहीं होंगे –