C# 在';我做错了一切
唉,我的程序某处有内存泄漏,但如果我知道它是什么,我会被诅咒的 它的工作是读入一堆~2MB的文件,进行一些解析和字符串替换,然后以各种格式输出它们。当然,这意味着有很多字符串,所以内存跟踪显示我有很多字符串,这正是我所期望的。程序的结构是一系列类(每个类都在自己的线程中,因为我是个白痴),它们作用于表示内存中每个文件的对象。(每个对象都有一个两端都使用锁的输入队列。这意味着我可以并行运行这个简单的处理,但也意味着我在内存中有多个2MB对象。)每个对象的结构由一个模式对象定义 我的处理类在完成处理后引发事件,并传递对包含我的所有字符串的大型对象的引用,以将其添加到下一个处理对象的队列中。将事件替换为要添加到队列的函数调用并不能阻止泄漏。其中一种输出格式要求我使用非托管对象。在类上实现Dispose()并不能阻止泄漏。我已经用索引名替换了对schema对象的所有引用。没有骰子。我不知道是什么原因,也不知道去哪里找。内存跟踪没有帮助,因为我看到的只是一堆正在创建的字符串,而我看不到引用在内存中的位置C# 在';我做错了一切,c#,memory-leaks,C#,Memory Leaks,唉,我的程序某处有内存泄漏,但如果我知道它是什么,我会被诅咒的 它的工作是读入一堆~2MB的文件,进行一些解析和字符串替换,然后以各种格式输出它们。当然,这意味着有很多字符串,所以内存跟踪显示我有很多字符串,这正是我所期望的。程序的结构是一系列类(每个类都在自己的线程中,因为我是个白痴),它们作用于表示内存中每个文件的对象。(每个对象都有一个两端都使用锁的输入队列。这意味着我可以并行运行这个简单的处理,但也意味着我在内存中有多个2MB对象。)每个对象的结构由一个模式对象定义 我的处理类在完成处理
在这一点上,我们很可能会放弃,但我有一种病态的需要知道我到底是怎么搞砸的。我知道堆栈溢出不能准确地梳理我的代码,但您可以建议什么策略来跟踪此泄漏?我可能会在我自己的时间里做这件事,所以任何方法都是可行的。我会尝试的一种技术是系统地减少演示问题所需的代码量,而不会让问题消失。这被非正式地称为“分而治之”,是一种强大的调试技术。一旦你有了一个小例子来演示同样的问题,你就会更容易理解。也许此时记忆问题会变得更清楚。只有一个人可以帮助你。那个人的名字是。(沉默) 但说真的。阅读她的博客(第一篇文章非常贴切)。看看她是如何调试这些东西的,会让你对你的问题有更深入的了解。我喜欢微软的。它为可视化托管堆和跟踪泄漏提供了一些很好的工具
托管调试外接程序(Strike之子)对于跟踪托管内存“泄漏”非常有用,因为根据定义,它们可以从gc根中发现 它将在WinDbg或Visual studio中工作(尽管它在许多方面更易于在WinDbg中使用) 这一点也不容易掌握。这是一个 我也支持这个建议,去看看苔丝·费尔南德斯的博客。我使用档案器来追踪内存泄漏。它比方法论上的试验和错误更具确定性,结果也更快
对于系统执行的任何操作,我都会拍摄一个快照,然后运行函数的一些迭代,然后再拍摄另一个快照。比较两者将显示在两者之间创建但未释放的所有对象。然后,您可以在创建堆栈帧时查看堆栈帧,从而确定哪些实例未被释放。您如何知道实际存在内存泄漏 还有一件事:您编写的处理类正在使用事件。如果您注册了一个事件处理程序,它将使拥有该事件的对象保持活动状态,即GC无法收集它。如果要对对象进行垃圾收集,请确保取消注册所有事件处理程序。获取以下信息:
内存和性能分析非常棒。能够看到正确的数字而不是猜测,这使得优化非常快。我在工作中经常使用它来减少主应用程序的内存占用。如果您的非托管对象确实是泄漏的原因,您可能希望它在分配非托管内存时调用
AddMemoryPressure
,并在Finalize
/Dispose
/中调用removeMoryPressure
。这将使GC更好地处理这种情况,因为它可能没有意识到需要安排收集,否则。请小心定义“泄漏”。“使用更多内存”甚至“使用过多内存”与“内存泄漏”不同。在垃圾收集环境中尤其如此。可能只是GC不需要收集您看到使用的额外内存。还要注意虚拟内存使用和物理内存使用之间的区别
最后,并非所有的“内存泄漏”都是由“内存”类问题引起的。有一次我被告知(没有被要求)修复导致IIS频繁重启的紧急内存泄漏。事实上,我做了分析,发现我在StringBuilder类中使用了很多字符串。我为StringBuilder实现了一个对象池(来自MSDN文章),
static unigned __int64 _foo_id = 0;
foo::foo()
{
++_foo_id;
if (_foo_id == MAGIC_BAD_ALLOC_ID)
DebugBreak();
std::werr << L"foo::foo @ " << _foo_id << std::endl;
}
foo::~foo()
{
--_foo_id;
std::werr << L"foo::~foo @ " << _foo_id << std::endl;
}