我们正在寻找应用程序中的一些内存泄漏,在进行某些操作(在我们的应用程序中加载和关闭一个项目)时,我们知道内存总是增加一点。
我们已经找到了很多它们,但是现在,10个以上增加最多的类是(根据我们的工具,ANTS Memory Profiler 8.2):
不幸的是,我不知道这是什么,所以我有点难以找到应该释放的内容。
我查看了实例树,但它一直都是微软的东西。
问题在于,当我们对项目进行“打开/关闭”时,我们会经历很多(大部分)代码。
编辑我们的应用程序的一部分对某些资源使用dynamic
关键字,它可能是链接的。这里的课程不是Disposable,我应该和他们做些什么吗?
编辑2
我很确定这与我的dynamic
内容有关,似乎C#在使用动态时会创建一个缓存。但是目前我不知道它为什么会增长(我一直加载相同的类,我将始终拥有完全相同的签名),也不知道如何清除它。
答案 0 :(得分:3)
我今天通过在我的应用RepoZ中分析内存泄漏来遇到完全相同的问题。该工具应该在后台运行,检查Git存储库并定期更新Windows资源管理器窗口标题。后一个任务必须对" Shell.Application"进行一些COM调用。找到资源管理器窗口并确定它们当前指向的路径。
使用dynamic
这样的关键字......
dynamic shell = Activator.CreateInstance(...);
foreach (object window in shell.Windows())
{
var hwnd = window.Hwnd;
...
}
......几个小时后我结束了这样的内存转储:
为了解决这个问题,我写了一些helper class called "Combridge"来发布COM对象并提供对底层COM对象的方法和属性的轻松访问。它非常简单明了,没什么特别的。它利用Reflection to COM objects,这就是为什么会有一些性能损失(见下文)。
有了它,上面的代码示例如下所示:
using (var shell = new Combridge(Activator.CreateInstance(...)))
{
var windows = shell.InvokeMethod<IEnumerable>("Windows");
foreach (var window in windows)
{
var hwnd = window.GetPropertyValue<long>("Hwnd");
...
}
}
您可以在RepoZ中看到文件ExplorerWindowActor的使用方式。
它不像dynamic
那样漂亮,并且在第一次尝试中表现也变差了。快速工作台显示如下:
我测试了1000次迭代,在每次迭代中,处理了10个打开的资源管理器窗口。对于每个窗口,在该COM对象上调用4个方法或属性。所以我们谈论的是40,000个COM电话。
持续时间从~2500ms(dynamic
)上升到~6000ms(Combridge
)。每次通话的时间从0.062ms到0.150ms。
所以这需要大约2.4倍的时间才能完成。
这很重要,我知道。但是我的要求没问题,而且内存泄漏也消失了。
那是它 - 我想与你分享这个故事,希望你能用这个类(或它的改进版本)来摆脱动态的地狱。
10小时后,RepoZ仍以非常恒定的内存占用率运行。
因此,打开10个资源管理器窗口,每个窗口4个COM调用,每秒两次完整循环,RepoZ创建 72.000个COM实例并进行 2.880.000个COM调用强烈>总体而言没有增加内存消耗。
我想我们可以说这个问题确实伴随着dynamic
。
答案 1 :(得分:1)
很少使用动态关键字,因为在大多数情况下,可以找到不需要它的变通方法。
根据您的应用程序,最好的建议是仔细考虑您是否可以设计您的解决方案,以避免动态。 以下是动态的一些有效用例:https://msdn.microsoft.com/en-us/library/dd264736.aspx
鉴于您确实需要使用动态,我建议您检测代码并找出哪些部分占用的内存最多。 确实使用动态会增加你的内存消耗,因为它需要执行各种lookups,但是为了有一个内存不足的异常,你需要使用很多动态变量来处理很多未知的事情。类型。
对于未知类型的调用方法有很多不同的ways,测量和调整瓶颈是可行的方法。
PS:另外,发布一些代码片段有很大帮助。