-1

经过一番阅读,我发现您在 C# 中编写的所有代码都是托管代码,不应该造成内存泄漏。然而,我的程序的行为方式暗示了某种内存泄漏。

我的整个程序归结为:( 目前我没有实际的代码)

while(true)
{
    //Source of the "leak"
    List<object> _objects = ReturnAllWindows(); 

    //Do something awesome with the list...

    System.Threading.Thread.Sleep(10);
}

ReturnAllWindows是一种pinvoke结合使用user32.dllEnumWindows获取当前打开的所有窗口的方法。

当我运行我的程序时,内存立即飙升,直到我得到一个OutOfMemoryException.

根据我的阅读,我唯一能想到的是函数中存在某种内存泄漏EnumWindows,但我很难想象 user32 没有得到完全管理。

那么发生了什么?我该如何预防/解决它?


编辑: 解决了,问题是这个列表后来与一些未正确处理的多线程结合使用。如果您评论该ReturnAllWindows行,则从未达到多线程,平台调用根本不是问题。

4

1 回答 1

1

如果是平台调用(即从托管代码调用本机、非托管方法),则很有可能内存没有以一种或另一种方式完全管理。对此稍加思考。编写本机、非托管应用程序的目的绝不是支持从托管代码调用。因此,对象作为非托管内存存在,由某些较低级别的系统(如果已开发)控制或不受控制。因此,从托管代码调用本机方法会执行所谓的装箱操作,它会创建一个包装本机内存的托管对象。

那么.NET 中是否存在内存泄漏?从技术上讲,没有。不是传统意义上的。但是垃圾存在的想法绝对是正确的。处理拳击只会进一步混淆(因为没有更好的术语)GC。

我认为在您的盒装数据列表的令人敬畏的操作中的某个地方应该取消对对象的引用。例如,如果您正在使用 foreach 遍历数据集合,并且在每个循环完成后您不再需要数据,则应删除对它的所有托管引用。例如,考虑以下示例:

List<object> foo = new List<object>(); // Imagine this is your list of data

foreach (var item in foo)
{
    // Execute an awesome expression here
}

看似无害,这些表达式永远不会释放内存,因为它总是以一种或另一种方式引用。内存优化版本如下:

List<object> foo = new List<object>(); // Imagine this is your list of data

while (foo.Count > 0)
{
    var item = foo[0];

     // Execute an awesome expression here

     item = null;
     foo.RemoveAt(0);
}

请注意,在第二个示例中,没有对资源的剩余引用,并且装箱的数据现在可以收集。现在这可能不是完整的问题,因为 .NET 中的内存问题通常很难追踪。也许考虑分析您的应用程序以更好地了解您的特定问题。希望这可以帮助。

于 2013-05-22T12:03:10.897 回答