2014-11-21 135 views
0

在過去的幾天裏,我一直試圖在應用程序中識別內存泄漏。我有充分的理由相信它來自這段代碼;Parallel.Invoke()可能的內存泄漏?

List<Item> Items = new List<Item>(); 
List<Action> Actions = new List<Action>(); 

while (true) 
{ 
    //The queue is a singleton which is used by multiple threads. 
    //This method grabs the lock and dequeues 500 items at a time. 
    Items = ItemQueue.Instance.DequeuePackageByAmount(500); 

    if (Items == null) break; 

    for (int i = 0; i < Items.Count; i++) 
    { 
     int copy = i; 
     Actions.Add(new Action(() => DoSomethingWithItem(Items[copy]))); 
    } 

    Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = 500 }, Actions.ToArray()); 

    Items.Clear(); 
    Actions.Clear(); 
} 

Item不包含任何應該丟棄的未管理資源。爲了完整性;

public class Item 
{ 
    public ICollection<string> SomeCollection; 
    public string SomeString; 
} 

而且,當然;

public void DoSomethingWithItem(Item item) 
{ 
    ItemProcessor processor = new ItemProcessor(); 
    processor.Process(item); 
} 

public class ItemProcessor 
{ 
    private DbContextWrapper db; 

    public ItemProcessor() 
    { 
     //DbContextWrapper contains methods which talk to the database. 
     //Every method has a using(), so there should be no DbContext resources 
     //left undisposed. 
     db = new DbContextWrapper(); 
    } 

    public void Process(Item item) 
    { 
     foreach(string s in item.SomeCollection) 
     { 
      //check some things and push it to the next queue if valid 
     } 
    } 
} 

我知道我不應該問請找內存泄漏因爲代碼是僞。因此;

是否有可能這段代碼易受內存泄漏的影響,如果是,哪裏?

編輯1:

爲了進一步解釋我有充分的理由相信,它來自這一段代碼;我已經測試了幾塊代碼,這塊是分配最多內存的塊。大約5分鐘後,我的應用程序使用大約1.6G RAM,不久之後,它崩潰了OutOfMemoryException

此外,爲了進一步解釋DbContextWrapper,它看起來像這樣;

AFAIK,這種方式應該沒有非託管資源留下不處理。

+0

你可以看看你的代碼幾個小時......或者你可以創建內存轉儲和分析它。你試過了嗎?或者你可以使用內存分析器 - 你試過了嗎? – 2014-11-21 11:41:28

+2

你說*我有充分的理由相信它來自這段代碼*和How?你有沒有介紹你的申請? – 2014-11-21 11:42:50

+1

在MaxDOP中指定500不會運行得更快,它只會導致492個不活動的任務,假設您有一個帶有超線程的四元代碼。爲什麼你想爲每個項目運行不同的操作,而不是僅僅對數據執行一個Parallel.ForEach?您無故創建500名代表。 – 2014-11-21 11:44:18

回答

1

如果沒有調試器/分析器等:
如果它是一個管理泄漏(不是非託管泄漏)你正在追捕你可以嘗試(我的記憶):

運行應用程序,直到你注意到了一個mem泄漏。 轉儲(發生異常之前!!)。
公開賽在WinDbg中並運行(假設.NET 4):

.loadby sos clr 
!dumpheap -stat 

然後看看最後一個對象列表(與大多數實例化對象),並確定你不會有很多實例期待的對象類型。 (你的一個或一個並行等)。該類型

運行:

!dumpheap -type [yourType] 

當心:結果列出所有以類似例子System.Threading.Thread名稱啓動類型。 你會得到類似(System.Threading.Thread的例子)的列表:

...//single objects list 
33767510 71d41144  56  
42fb29e4 71d41144  56  
42fbf2f0 71d41144  56  
42fd6e18 71d41144  56  
42fe62b0 71d41144  56  
430715fc 71d41144  56  
4344374c 71d41144  56  
total 372 objects 
Statistics: // summary of the classes listed in single object list 
     MT Count TotalSize Class Name 
71d2ebd8  1   24 System.Threading.ThreadPoolRequestQueue 
714c52b4  1   32 System.Threading.ThreadExceptionEventHandler 
71d40f44  2   144 System.Threading.ThreadAbortException 
71d285a4  41   820 System.Threading.ThreadHelper 
71d27f48  82   2624 System.Threading.ThreadStart 
>>71d41144  245  13720 System.Threading.Thread 

第一部分是內存中的所有對象的列表。列表中的標記類型是爲示例選擇的那個。
對象列表中的第二個參數是類型的方法表。這是如何識別對象列表中的不同類型。
採取幾個對象列表(如42fd6e18或4344374c例如)的地址,並且運行:

!gcroot <address> 

數的地址的。您將獲得持有對可疑類型的引用的對象的列表。你必須找到列表頂部的對象的原因,爲什麼它保持你的類型(實際上你認爲它不應該)