2009-07-06 88 views
9

我在混合模式C++/CLR .NET应用程序中遇到内存泄漏缓慢的问题。混合模式C++/CLR应用程序中的内存泄漏

(链接到VS2008 C++/CLR的Windows窗体应用程序与 “/ CLR” 编译器设置它的C++原生静态库)

典型行为:应用程序开始使用30 MB(专用内存)。然后泄漏内存速度缓慢,例如在模拟重负载下运行时每小时一个MB。这模拟了应用程序在几天或几周内正在运行。

我一直在使用一些工具来跟踪内存泄漏既包括随Visual Studio的CRT库的CRT调试的东西尝试。我还使用了商业泄漏检测工具(“Memory Validator”)。

两个报告在关机时可忽略不计的内存泄漏(我不是担心一些小的条目数量到几KB)。另外,我可以看到在运行时,跟踪的内存看起来不那么重要(所以我不相信这只是内存,只在应用程序退出时释放)。我获得了大约5 MB的上市内存(总数> 30MB)。

所述的工具(存储器验证器)是设置跟踪所有的内存使用情况(包括malloc的,新的,虚拟存储器分配和一大堆其它类型的存储器分配的)。基本上,每个设置的内存来跟踪已被选中。

在.NET图像报告它周围使用1.5 MB的存储器(从性能监视器)。

这里是信息的最后一点:我们有一个版本,它运行作为本地控制台应用程序应用程序的(纯天然 - 不CLR在所有)。除了没有UI的东西外,这与混合模式的95%相同。这似乎并没有泄漏内存,并在专用字节大约5MB处出现峰值。

所以基本上我试图让人们在这里要说的是,我不认为任何本地代码的泄漏内存。

另一块拼图:我发现这个目标2.0框架(对此我),当是指内存泄漏在混合模式下的应用:http://support.microsoft.com/kb/961870

不幸的是,细节僵硬稀疏,所以我不知道这是相关的。我确实尝试了针对3.5框架而不是2.0,但仍然有同样的问题(也许我没有这样做)。

任何人有任何建议吗?

几件事情,可能会帮助我:

  • 是否有任何其他种类的,我不是跟踪内存分配的?
  • 这些数字如何不加起来?我获得了5 MB的CRT内存使用量,1.5 MB的.NET内存,那么整个应用程序如何使用30 MB专用字节?这一切都绑在.NET框架?为什么我没有看到这些泄漏工具? .NET框架不会显示为某种分配的内存吗?
  • 任何其他泄漏检测工具,适用于混合模式应用程序?

感谢所有帮助

约翰

+0

.NET 2.0和.NET 3.5都使用相同的CLR 2.0,因为您可以从版本号轻松看到;-) – 2009-07-16 07:29:20

回答

6

好的,我终于找到了问题。

这是由于/ EH(异常处理)的设置不正确引起的。

基本上,使用混合模式的.NET应用程序,您需要确保所有静态链接的库都使用/ EHa而不是默认/ EH进行编译。

(软件本身还必须与/ EHA编译,但是这是一个给定的 - 编译器,如果你不使用它会报告错误的问题是,当你在其他静态本地库链接。)

问题是,使用/ EHs编译的本机库中引发的应用程序管理位中捕获的异常最终无法正确处理异常。然后C++对象的析构函数不能正确调用。

在我的情况下,这只发生在一个罕见的地方,因此为什么花了我很多时间来发现。

0

试用:DebugDiags
生成一些内存转储后,它会给你一个很好的内存分配的总结,并且根据找到你的PDB,它可以告诉你它被分配的人。

+0

谢谢我会试试 – John 2009-07-09 10:18:07

0

您可能有参考泄漏,请查看ANTS分析软件。 Ants Profiler

引用泄漏是内存泄漏的.net等价物,您持有对对象的引用,从而阻止它被垃圾收集,因此您使用的内存开始增加。

+0

但是不会在“##所有堆中的字节“.NET内存值? 我一直在Process Explorer中看到它,它不会泄漏。 泄漏是私有字节,但不是“所有堆中的#字节”。 – John 2009-07-09 10:17:31

0

是否有可能您错过了一些垃圾处理器,如果您使用GDI +和其他许多API,可能会发生这种情况。

如果您运行静态分析工具FXCop,它有一个规则来检查您是否在提供接口的对象上调用了dispose(或使用“using”)语句。在.Net中,如果函数使用非托管代码,它通常会为您提供一种处理或关闭方法,以避免泄漏资源/内存。

+0

好主意。我猜这些泄漏不会显示为CLR内存使用,因为它们是本地的,但也不会出现在本机泄漏检测工具中,因为它们不是我的代码。 我会给一个bash(我不知道FXCop是否可以处理混合模式的C++/CLI) – John 2009-07-16 10:17:33

+0

希望它有帮助。我只是在黑暗中拍摄,但我发现在使用GDI的应用程序中发生了这种情况,我发现几乎GDI +中的每个对象都需要一个处理器。请注意,这是“使用” – Spence 2009-07-16 12:09:47

4

像斯宾塞说的,但对于C++/CLI)....

对于任何对象,您使用的是C++/CLI中,如果你创建更多的对象,从你的C++代码,你应该尝试使用堆栈分配语法,尽管这是一种编译器的神奇事物,但它可以设置嵌套的__try {} __finally {}语句,您可能习惯使用本地代码(这是以某种方式设置它们的方式)放弃对Dispose的调用)。

Nish'sarticle at the code project here关于C++/CLI堆栈分配语义非常好,深入探讨了如何使用{}进行模拟。

你也应该确保删除任何对象是implment IDisposable的,因为你不能调用Dispose在C++/CLI,删除这是否适合你,如果你不使用栈语义..

我通常所说的关闭自己在Streams上,并在完成对象的时候尝试分配nullptr,以防万一。

您可能还需要检查出this article on memory issues,perticularly有关事件的用户,如果您分配事件对你的对象,你可能会被泄露......

作为最后的手段(或者先:),一个我曾经做过的事情是利用CLR profiler API,here's another article就如何做到这一点,作者的作者(杰伊Hilyard)有一个例子,答案;

  • 使用的每个.NET类型,如何 许多对象实例被分配 ?
  • 每种类型的实例 有多大?
  • 什么通知 GC提供,因为它通过垃圾回收去 什么 你可以找到?
  • GC 何时收集对象实例?

应该让你比一些商品探查一个更好的主意,我注意到,他们可以偶尔会误导取决于你的配置porofile(顺便说一句,注意大对象堆的问题,>〜83KB的对象会被特殊处理,在这种情况下,我会推荐,离开大堆物体:)。

考虑您的意见,一些事情......

我有关图像负载不是计费配额或其他任何disernable统计之前已经发布,这是什么意思,你可能需要跟踪一些手柄或装载机问题(最终会看到loader loader),但在此之前,你可以尝试设置一些Constrained Execution Regions,它们可以创造奇迹,但不幸的是很难修改为非纯代码。

这最近MSDN Mag,文章文件的许多perfmon类型的内存sperlunking(后续this older one)。

来自VS Perf Blog,他们展示了如何在Visual Studio中使用SOS,它可以方便地追踪胭脂DLL的相关帖子也很好。

Maoni Stephen's Blog and company,他说他是在perf队,但他的职位基本上100%都是关于GC的,所以他可能写得很好。

Rick Byers是一位拥有CLR诊断团队的开发者,他的许多博客伙伴也是不错的消息来源,但是,我强烈建议也提及相当新的dev/diagnostics forum。他们最近扩大了他们的讨论范围。

Code Coverage Toolstracing通常可以提供帮助,让您了解实际运行的内容。 (具体来说,那些相关的统计数据可能不会给你一个关于什么是你的代码的全局视图,我可以说最近我发现(即使使用.net4beta二进制文件,this company的分析器也是相当不错的,它能够从它的配置文件轨迹中导出本机/管理泄漏,将您带回到确切的源代码行(即使经过优化,相当不错(并且它有30天的试用版))))。

祝你好运!希望这对我有帮助,因为我现在正在做很多相同的工作;)