2012-05-09 14 views
14

कोडप्रतिनिधियों को स्मृति रिसाव का कारण बन सकता है? GC.TotalMemory (सही) तो

using System; 
internal static class Test 
{ 
    private static void Main() 
    { 
     try 
     { 
      Console.WriteLine("{0,10}: Start point", GC.GetTotalMemory(true)); 
      Action simpleDelegate = SimpleDelegate; 
      Console.WriteLine("{0,10}: Simple delegate created", GC.GetTotalMemory(true)); 
      Action simpleCombinedDelegate = simpleDelegate + simpleDelegate + simpleDelegate; 
      Console.WriteLine("{0,10}: Simple combined delegate created", GC.GetTotalMemory(true)); 
      byte[] bigManagedResource = new byte[100000000]; 
      Console.WriteLine("{0,10}: Big managed resource created", GC.GetTotalMemory(true)); 
      Action bigManagedResourceDelegate = bigManagedResource.BigManagedResourceDelegate; 
      Console.WriteLine("{0,10}: Big managed resource delegate created", GC.GetTotalMemory(true)); 
      Action bigCombinedDelegate = simpleCombinedDelegate + bigManagedResourceDelegate; 
      Console.WriteLine("{0,10}: Big combined delegate created", GC.GetTotalMemory(true)); 
      GC.KeepAlive(bigManagedResource); 
      bigManagedResource = null; 
      GC.KeepAlive(bigManagedResourceDelegate); 
      bigManagedResourceDelegate = null; 
      GC.KeepAlive(bigCombinedDelegate); 
      bigCombinedDelegate = null; 
      Console.WriteLine("{0,10}: Big managed resource, big managed resource delegate and big combined delegate removed, but memory not freed", GC.GetTotalMemory(true)); 
      GC.KeepAlive(simpleCombinedDelegate); 
      simpleCombinedDelegate = null; 
      Console.WriteLine("{0,10}: Simple combined delegate removed, memory freed, at last", GC.GetTotalMemory(true)); 
      GC.KeepAlive(simpleDelegate); 
      simpleDelegate = null; 
      Console.WriteLine("{0,10}: Simple delegate removed", GC.GetTotalMemory(true)); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
     Console.ReadKey(true); 
    } 
    private static void SimpleDelegate() { } 
    private static void BigManagedResourceDelegate(this byte[] array) { } 
} 

इंगित करने के लिए आउटपुट

GC.TotalMemory(true) 
    105776: Start point 
    191264: Simple delegate created 
    191328: Simple combined delegate created 
100191344: Big managed resource created 
100191780: Big managed resource delegate created 
100191812: Big combined delegate created 
100191780: Big managed resource, big managed resource delegate and big combined delegate removed, but memory not freed 
    191668: Simple combined delegate removed, memory freed, at last 
    191636: Simple delegate removed 
+0

निष्पादन योग्य repro के लिए धन्यवाद, बीटीडब्ल्यू! – usr

उत्तर

17

दिलचस्प मामला लगता है। यहाँ समाधान है:

enter image description here

का मेल प्रतिनिधियों observationally शुद्ध है: ऐसा लगता है प्रतिनिधियों के बाहर करने के लिए अडिग हैं की तरह। लेकिन आंतरिक रूप से, मौजूदा प्रतिनिधियों को संशोधित किया जा रहा है। वे कुछ स्थितियों के तहत साझा करते हैं, वही _invocationList प्रदर्शन कारणों से (परिदृश्य के लिए अनुकूलित करना कि कुछ प्रतिनिधि एक ही घटना में शामिल होते हैं)। दुर्भाग्यवश, _invocationListsimpleCombinedDelegate के लिए bigMgdResDelegate संदर्भित करता है जो स्मृति को जीवित रखने का कारण बनता है।

+1

छवियों और सब कुछ के साथ उत्कृष्ट जवाब। –

+0

वाह, यह आश्चर्यजनक है! लेकिन क्या यह वास्तविक उत्परिवर्तन है, या एक चालाक स्थानीय अनुकूलन है? शायद संकलक/जेआईटी विधि में आगे दिखता है और पहले प्रतिनिधि बनाने से पहले एक पूर्व-जनसंख्या 4-तत्व सरणी बना देता है? – Weeble

+0

@Weeble, सुनिश्चित नहीं है कि आप जेआईटी-अनुकूलन के संबंध में क्या मतलब रखते हैं लेकिन जेआईटी आमतौर पर सुंदर गूंगा है। यह इस तरह परिष्कृत सामान नहीं करता है। वैसे भी, जब आईआईएल कोड आदेश देता है तो जेआईटी केवल सामान को बदल सकता है। यह * कभी * उत्परिवर्तन खुद को पेश नहीं करता क्योंकि यह असुरक्षित होगा। – usr

1

मुझे यहां बिंदु याद आ रहा है, लेकिन कचरा संग्रह डिजाइन द्वारा गैर-निर्धारिती है। Ergo, यह तय करने के लिए .NET ढांचे पर निर्भर करता है कि यह स्मृति को पुनः प्राप्त करता है।

आप एक साधारण पाश में जीसी.गेटटॉटलमेमरी चला सकते हैं और विभिन्न आंकड़े प्राप्त कर सकते हैं। शायद कोई आश्चर्य नहीं कि दस्तावेज निर्दिष्ट करता है कि लौटाया गया आंकड़ा एक अनुमान है।

+0

मुख्य रूप से इस उत्तर से सहमत हैं क्योंकि ओपी प्रस्तावों का परीक्षण उपयोगी कुछ भी पता लगाने के लिए बहुत आसान है। प्रबंधित वातावरण में 'लीक मेमोरी' आमतौर पर खराब डिजाइन किए गए कोड (स्थिर वस्तुओं को चीजों की सूचियों के संदर्भ में संदर्भित करने के लिए उबालती है।) इस गेम में इस बिंदु पर जीसी में कोई वास्तविक बग नहीं मिल रहा है। – Sprague

+0

GetTotalMemory स्पष्ट जीसी करता है। यह परीक्षण काफी विश्वसनीय है। यह भी ध्यान दें कि इस परीक्षण में अन्य सभी मामलों में वेरिएबल्स बाहर निकलने का काम करता है (आगे के साक्ष्य कि यह अपेक्षित के रूप में काम करता है)। – usr

+0

मुझे लगता है कि ओपी का मुद्दा यह है कि 'जीसी.गेटटॉटलमेमरी (सच)' को संग्रह को मजबूर करना है, लेकिन दोनों बड़े प्रतिनिधियों को हटाने और संग्रह को मजबूर करने के बाद, स्मृति अभी भी आवंटित की गई है। –