2011-03-18 8 views
6

मैं नए समवर्ती संग्रह में पढ़ रहा हूं और विशेष रूप से ConcurrentBag मेरा ध्यान मिला है। चूंकि ConcurrentBag आंतरिक रूप से वस्तुओं का ट्रैक रखने के लिए प्रत्येक व्यक्तिगत थ्रेड पर स्थानीय सेट रखता है, इसका मतलब है कि जब धागा स्वयं स्कोप से बाहर हो जाता है, तब भी इसे ConcurrentBag द्वारा स्मृति में संदर्भित किया जाएगा। बदले में इसका मतलब धागा, साथ ही मूल संसाधनों द्वारा दावा किया गया दोनों स्मृति है? (.NET थ्रेड ऑब्जेक्ट के सटीक आंतरिक कार्य को जानने के लिए मुझे क्षमा करें)ConcurrentBag में संभावित मेमोरीकैक?

मैं एक उपयोगिता मान सकता हूं जहां आपके पास एक बहुभाषी webservice के लिए 1 वैश्विक ConcurrentBack है जहां आपके पास बहुत से ग्राहक कार्य जोड़ रहे हैं। इन कार्यों को थ्रेडपूल पर धागे द्वारा जोड़ा जाता है। अब थ्रेडपूल धागे को प्रबंधित करने का एक बहुत ही प्रभावी तरीका है लेकिन यह काम की मात्रा के आधार पर थ्रेड को हटा देता है और बनाता है। इसलिए, इस तरह की एक webservice कभी-कभी परेशानी में पड़ सकती है क्योंकि अंतर्निहित बैग अभी भी कई लोगों को संदर्भित किया जाना चाहिए-नष्ट धागे होना चाहिए।

मैं इस व्यवहार को परीक्षण करने के लिए एक त्वरित एप्लिकेशन बनाया:

static ConcurrentBag<int> bag = new ConcurrentBag<int>(); 
    static void FillBag() { for (int i = 0; i < 100; i++) { bag.Add(i); } } 
    static void PrintState() { Console.WriteLine("Bag size is: {0}", bag.Count); } 
    static void Main(string[] args) 
    { 
     var remote = new Thread(x => 
     { 
      FillBag(); 
      PrintState(); 
     }); 
     // empty bag 
     PrintState(); 
     // first 100 items are added on main thread 
     FillBag(); 
     PrintState(); 
     // second 100 items are added on remote thread 
     remote.Start(); 
     remote.Join(); 
     // since the remote thread is gone out of scope, what happened to its local storage which is part of the bag? 
     PrintState(); 
     // now force a cleanup 
     WeakReference weakRemoteReference = new WeakReference(remote); 
     remote = null; 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     // Now check if the thread still exists 
     if (weakRemoteReference.IsAlive) 
      Console.WriteLine("Remote thread still exists"); 
     PrintState(); 
     Console.ReadLine(); 

और उत्पादन मेरी कहानी की पुष्टि करता है:

Bag size is: 0 
Bag size is: 100 
Bag size is: 200 
Bag size is: 200 
Remote thread still exists 
Bag size is: 200 

इस व्यवहार की उम्मीद की जा करने के लिए है, मैं अपने परीक्षण में एक गलती करते हैं किया या इसे एक डिजाइन दोष माना जा सकता है?

+0

ध्यान दें कि मैं रिमोट थ्रेड का नाम गुंजाइश से बाहर चला गया हूं, अभी भी इसका दायरा है और कह सकता है: "चूंकि रिमोट थ्रेड समाप्त हो गया है" – Polity

उत्तर

8

ConcurrentBag वास्तव में चीजों को स्थानीय भंडारण में रखता है, और यदि आप धागे को छोड़ देते हैं तो मेमोरी लीक का कारण बन सकता है। हालांकि, कार्यान्वयन एक धागे की सूची से वस्तुओं को "चोरी" करने में सक्षम है ताकि दूसरे थ्रेड को दिया जा सके। आप कार्रवाई में देख सकते हैं यदि आप निम्न लिखें: आपको लगता है कि कार्यक्रम चलाते हैं

ConcurrentBag<int> MyBag = new ConcurrentBag<int>(); 

void DoIt() 
{ 
    for (int i = 0; i < 10; ++i) 
    { 
     MyBag.Add(i); 
    } 

    ThreadPool.QueueUserWorkItem(EmptyBag); 

    Console.Write("Press Enter:"); 
    Console.ReadLine(); 

    Console.WriteLine("{0} items in bag", MyBag.Count); 
} 

void EmptyBag(object state) 
{ 
    int take; 
    while (MyBag.TryTake(out take)) 
    { 
     Console.WriteLine(take); 
    } 
    Console.WriteLine("Bag is empty"); 
} 

और "बैग खाली है" संदेश तक इंतजार Enter दबाने के पहले, आप देखेंगे कि बैग वास्तव में खाली कर दिया है।

तो, जब तक बैग से एक धागा पढ़ा जाता है, तो अंततः खाली हो जाएगा। भले ही सभी वस्तुओं को अन्य धागे से जोड़ा गया हो।

तो, हाँ, एक संभावित स्मृति रिसाव है। अभ्यास में, हालांकि, यदि बैग के कई धागे तक पहुंच रहे हैं, तो यह चिंता का विषय नहीं है।

+0

मैं अनुमान लगा रहा हूं कि दो धागे यहां हैं, और QueueUserWorkItem एक नए धागे को जन्म देता है । लीक (स्रोत, या चोरी की गई प्रतिलिपि) कौन सा धागा है? मैं इस प्रक्रिया को कैसे बाधित कर सकता हूं और इसे बंद कर सकता हूं? मैं एक कार्य में एक रद्द टोकन का उपयोग कर रहा हूं ... – LamonteCristo

+0

@ makerofthings7: इस उदाहरण कोड में, मुख्य धागा बैग का मालिक है, और 'QueueUserWorkItem' द्वारा उत्पन्न थ्रेड बैग खाली करता है। इस उदाहरण में कुछ भी लीक नहीं है। आम तौर पर, यदि आप बैग में चीजें जोड़ते हैं और उन्हें बाहर नहीं लेते हैं तो वहां एक रिसाव होगी। यदि आप अधिक जानकारी चाहते हैं तो आप एक प्रश्न पोस्ट करने पर विचार कर सकते हैं। –

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