必须从基于.Net服务器的Windows应用程序调用遗留的c ++应用程序,这些应用程序有时会出现臭名昭着的内存泄漏问题。 .Net垃圾收集时间是不可确定的,有时c ++对象被“销毁”或不“按时”销毁,产生不可预测的结果,并且通常会使c#web应用程序崩溃。将c ++对象尽可能频繁地推送到垃圾回收堆栈的最佳方法是什么,但不是经常删除对COM对象的.Net引用。请记住,COM对象可以生成子对象,因此COM对象的.Net引用计数可以仅通过函数调用而更改,而不一定是实例化。
由于发生了内存泄漏并且COM对象未被清除,性能会降低,直到它慢到IIS自身跳闸几次然后崩溃为止。重新启动IIS可以解决问题直到下次。定期重启会有所帮助,但忙碌的一天可能会在工作日造成这种情况。
几年前我必须使用.Net 1.1来解决这个问题。想知道其他人是否有我的解决方案或更好的解决方案。这不是ASP.NET。这是一个.Net dll。
最终结果并不完全令人满意,网络服务器每隔几个月就会崩溃。
答案 0 :(得分:1)
你问“尽可能频繁地将c ++对象推送到垃圾收集堆栈的最佳方法是什么”,但c ++对象永远不会被垃圾收集。也许这样看......
您有一个实例化一堆c ++对象的进程。其中一些c ++对象实现了COM对象,因此它们的生命周期通过AddRef / Release进行管理。其中一些COM对象被导入.NET世界,并用RCW(运行时可调用包装器)包装。只有RCW是.NET对象并进入垃圾收集堆。
如果没有您的任何干预,RCW最终将进行GC,当发生这种情况时,它将针对其底层COM对象执行释放。如果要立即释放COM对象而不等待GC,可以调用...
System.Runtime.InteropServices.Marshal.ReleaseComObject
...甚至是FinalReleaseComObject,如果你确定它是你想要的。
回到你的问题:你想知道如何在不释放对COM对象的.NET引用的情况下删除c ++对象。由于.NET堆中不存在c ++对象,因此无法直接实现此目的。您可以从COM对象中公开一个删除其所有c ++对象的方法,并从.NET代码中调用该方法。但我想如果你的COM对象有可能识别出你已经做过的所有泄露的c ++对象。
希望我已经解释了为什么没有办法在你的问题中实现你的建议,但是有很多工具可以帮助你找到并修复你的内存泄漏。我建议使用LeakDiag这样的工具(搜索StackOverflow)来找出你的c ++代码泄漏内存的位置。
如果您使用的是IIS6或更高版本,那么实用的解决方案是配置应用程序池回收。你可以调整这些数字,以便在它们泄漏足够的内存之前杀死并重新启动进程是有问题的,并且它通常以用户不会注意到任何停机时间的方式工作。
答案 1 :(得分:0)
创建一个COM +应用程序并将您使用的COM类放在该应用程序中。这样,所有COM对象都在一个单独的进程中实例化。您可以定期释放所有COM对象,然后重新启动COM +应用程序进程。