2014-11-21 93 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> 

数的地址的。您将获得持有对可疑类型的引用的对象的列表。你必须找到列表顶部的对象的原因,为什么它保持你的类型(实际上你认为它不应该)