Parallel.Invoke()可能出现内存泄漏?

时间:2014-11-21 11:37:33

标签: c# memory-leaks

在过去的几天里,我一直在尝试识别应用程序中的内存泄漏。我有充分的理由相信它来自这段代码;

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,它看起来像这样;

public class DbContextWrapper
{
    private string ConnectionString;

    public DbContextWrapper()
    {
        //Create ConnectionString with EntityStringBuilder etc.
    }

    public int AnyMethod(int someExistingId)
    {
        using(DbContext db = new DbContext(ConnectionString))
        {
            return db.table.Where(t => t.id == someExistingId).First();
        }
    }
}

AFAIK,这样就不会有任何不受管理的非托管资源。

1 个答案:

答案 0 :(得分:1)

如果您没有调试器/分析器等:
如果它是一个托管泄漏(不是非托管泄漏)你正在追捕你可以尝试(在我的记忆中):

运行应用程序直到发现内存泄漏。 转储(在异常发生之前!!) 在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>

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