My(C#.NET 4.0)应用程序运行一段时间,根据从SQLite数据库获取的价格变化更新模拟帐户。
我在任何特定日期需要的是当前状态的帐户和最新价格。我希望垃圾收集器可以将内存使用率保持在一个相当均匀的龙骨上:我看到的是工作集和私有内存(由System.Diagnostics.GetCurrentProcess()
报告)和{{1}中的稳定增长}:在这种情况下每天约300K。不可避免地,整个事情在大约12个模拟年后崩溃,此时内存使用量增加了大约1GB。
内存使用率或多或少线性增加(如果我在每天结束时强制GC.GetTotalMemory(true)
,则会非常顺利)。
我推断一些对象在某种程度上不是垃圾收集的,即使我认为对它们没有进一步的需要,并且预计它们会在正常的退潮和执行流程中被清理干净。
我可以尝试确定哪些地方无意中造成了这种情况?
我已经下载并运行了CLRProfiler - 它会花费周末的最佳时间来消化文档,并且无法保证它能够提供帮助。
我正在研究this question中的参考资料。一般来说,我知道什么样的情况可能会导致问题,我更感兴趣的是看看是否有更快的方法来识别细节,而不花费宝贵的时间来处理我的代码,勾选参考文献......
注意:问题似乎与事件无关,并且没有涉及图形组件。
答案 0 :(得分:7)
您说您可以模拟工作负载以导致应用程序崩溃。要快速查找泄漏,请模拟工作负载,直到内存消耗变得很大(例如100 MB),将WinDbg或VS与非托管调试连接到您的进程并立即运行:
.load sos
extension C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded
!dumpheap -stat
total 2885 objects
Statistics:
MT Count TotalSize Class Name
7a5eab18 1 12 System.Diagnostics.TraceOptions
(lots of unimportant stuff here)
79332b54 304 7296 System.Collections.ArrayList
79333274 56 11640 System.Collections.Hashtable+bucket[]
793042f4 345 50056 System.Object[]
79330b24 1041 99428 System.String
79332cc0 21 107109728 System.Int32[]
从此(已排序)输出中,您可以告诉您int[]
类型存在问题。类型:
!DumpHeap -type System.Int32[] (or whichever type you got)
Address MT Size
01381a1c 7931e9bc 40
(cut)
075d1000 79332cc0 67108880
03811000 79332cc0 40000016
total 22 objects
Statistics:
MT Count TotalSize Class Name
7931e9bc 1 40 System.Int32[][]
79332cc0 21 107109728 System.Int32[]
Total 22 objects
现在您拥有对象的地址。选择其中一个并运行
!GCRoot 075d1000
你会得到泄漏的原因。另外,您可能需要咨询this tutorial。
答案 1 :(得分:3)
你在使用活动吗?如果对象A
订阅了对象B
上的事件,则B
正在存储对A
的引用。因此,在A
可以进行垃圾回收之前,不能对B
进行垃圾回收。如果A
取消订阅B
,则会移除B
对A
的引用。
答案 2 :(得分:2)
我建议将其作为一种启发式方法寻找的东西是你可能在一个较长寿的实例中附加一个事件的地方。如果你有一些实例在你的应用程序的生命周期中坚持下去,并且你有较短的生活类来监听它上面的事件,那么如果不解开这些事件将导致垃圾收集器跳过你的短生命对象,因为更长寿的物体挂在它们的引用上,直到你分开。
编辑:对于它的价值,你可能想看看Ants Memory Profiler。我不知道它与你正在看的那个相比如何,但是从试过它之后,它的学习曲线也不算太差,所以你可能花更少的时间搞清楚它。