使用GC和LOH正确识别内存泄漏

时间:2015-01-19 20:16:33

标签: c#-4.0 memory-management garbage-collection

这可能会被问到几种不同的方式,但这对我来说是一个相对较新的领域,所以请原谅我,如果它是多余的并指出我的路上。

基本上我创建了一个数据采集引擎,它可以获取高速数据(每秒高达数千个点)并将它们存储在数据库中。

数据库是动态的,因此提供给数据库的语句也是在代码中动态创建的,这反过来需要大量的字符串操作。但是,所有字符串都在异步事件处理程序方法的范围内声明,因此一旦方法完成,它们就应该超出范围。

当这个应用程序运行时,根据任务管理器/进程资源管理器的内存使用情况,缓慢但稳定地增加,所以看起来某些东西没有被正确处理和收集。

如果我附加CDB -p(是的我从CLR加载sos.dll)并执行!dumpheap我看到System.String正在使用它的大部分,如果我!dumpheap -type System.String和!执行地址我看到了确切的字符串(SQL语句)。

然而,如果我在任何一个地址上做了一个!gcroot,我会找到0个独特的根(运行'!GCRoot -all'查看所有根)。"反过来,如果我尝试,因为它表明我得到"无效的参数-all" O.o

所以经过一些谷歌搜索后,有关无根对象的一些论点最终会被GC收集,这不是问题。我看了看,看来84%的问题是坐在LOH上(其中取决于你看哪个线程,可能会或可能不会为GC 处理,除非机器上有内存约束或我明确告诉它收集根据我能找到的一切被认为是坏的)

所以我需要知道的是,这基本上是真的,这不是内存泄漏,只是系统将东西留在那里直到它被回收,如果是这样,那么我怎么告诉我做的或者没有合法的内存泄漏。

这是我第一次在应用程序外部使用调试器,因为我以前从未解决过这类问题,所以我对这一部分很新,这是一种学习经验。

应用程序是用VS2012 Pro,C#编写的,它是多线程的,控制台应用程序正在包装API以进行测试,但最终将成为Windows服务。

1 个答案:

答案 0 :(得分:0)

您阅读的内容是真实的,托管应用程序使用内存模型,其中对象堆积在您达到特定内存阈值(根据系统上的物理内存量和应用程序的实际增长率计算),之后所有(*)"死"对象被剩余的有用内存压扁,使其成为分配速度的一个连续块。

所以是的,不要担心你的记忆会逐渐增加,直到你的几十MB并没有收集。

(*) - 实际上更复杂的是多个内存池(基于对象大小和生命周期长度),这样系统就不会经常探测非常长寿的对象,并且通过终结器。当一个对象有一个终结器而不是被释放时,内存会被挤压它们但它们会被移动到一个特殊的队列,即终结器队列,它们等待终结器在UI线程上运行(请记住GC运行在一个单独的线程上),然后它才最终被释放。