我有一个事件驱动的应用程序,我负责维护。 在不同的计时器上,每30秒运行大约100个事件。随着时间的推移,事件变为每秒约1-3个事件的恒定流。 内存使用量似乎不依赖于在任何给定秒内触发的事件数。 每个事件都会轮询来自Web服务的数据,使用LINQ2SQL DataContext检查数据以防止先前轮询的数据(完成后我不会处理或清空DataContext),如果数据不同,则更新数据库并将新数据推送为通过TCP向接收方服务发送XML消息。
此应用似乎有内存泄漏
特点: 启动时,程序使用~30MB。随着时间的推移,任务管理器中的内存使用将开始进行,首先只是略微,在50到150MB之间,并最终变得更糟,在200MB和1GB +之间振荡。当发生这种情况时,它会在一两秒钟内发生几次,然后在接下来的10-20秒左右稳定在150MB左右。
我一直在尝试使用内存分析来捕捉这种行为。到目前为止,我一直没有成功,我无法将应用程序带到pogo或在内存使用情况下振荡,就像探测器不在观看时一样。 然而,我一直注意到内存使用上的方波模式,因为垃圾收集器阶段1和2运行看起来非常类似于我在任务管理器中看到的,除了方波中的内存使用振荡是宽10MB,而不是800MB +(200MB到1GB +)。现在,根据谷歌图片,正常运行的应用程序中的垃圾收集看起来更像是锯齿波,而不是方形。
我坦率地看不出我的应用程序在一秒钟之内可以在200MB到1GB +内存使用量之间进行任何操作,而不会将CPU加速到100%。
我已经阅读了垃圾收集+事件处理之间可能出现的一些问题,但我有几条路可以调查,并且正在努力缩小哪一个花时间。我在.NET上的速度仍然很慢,并没有为运行C的嵌入式设备开发出“直觉”,这通常可以帮助我过滤我应该先调查的内容。 如果FEELS喜欢的话可能是某些事件处理程序正在丢失并重新获得[大量数据]的引用(我不知道这甚至会发生什么?)看到内存使用情况似乎很快就会回升到1GB垃圾收集器运行并将内存使用量减少到200MB。
此应用的早期版本没有这些问题。自那时以来我做出的两项改变包括
我想我现在的主要问题是
编辑:事件具有基于实例的订阅,如讨论here,并且在应用程序的生命周期内永远不会取消订阅。
edit2:终于设法在探查器中捕获它,似乎是以某种方式创建的200MB system.string。感谢大家排除GC行为。
答案 0 :(得分:4)
大多数情况下,内存泄漏是由对象之间的奇怪引用引起的(此处还包括事件和委托)。
我认为您可以尝试以下内容:
运行以下命令:
.symfix
.loadby sos clr
!dumpheap -type [YourAssemblyNameSpacePrefix] -stat
最后一个命令将为您提供内存中不是CLR类型的所有实例,只提供您的类型。查看具有大量实例的类型,并尝试查看是否有任何不正确的内容。
如果您看到大量相同类型的对象运行以下命令,该命令将显示所有实例的地址:
!dumheap -type [TheFullObjectTypeName]
您需要选择一个实例地址。现在运行以下命令以查看对该实例的引用:
!gcroot [InstanceAddress]
对于不同的实例重复步骤6几次,以便您可以确认泄漏来自同一个地方,或者帮助您确定导致这些实例未被收集的原因(仍被其他对象引用)。
如果您没有看到任何与您自己的类型有关的怪异,请将步骤4中的!dumpheap命令更改为:!dumpheap -stat。这样您就不会按类型过滤,也会看到CLR类型和第三方库类型。
这有点复杂,但希望我能给你一个方法来帮助你弄清楚如何找到内存泄漏。