如何强制回收无法取消引用的对象的垃圾?

9
我们正在使用EWS Managed API轮询MS Exchange以获取新的邮件消息,每次调用轮询方法(PullSubscription.GetEvents())时,Microsoft的API未能正确处理NetworkStream的释放,导致内存成比例地增加。这个问题之前曾经在这里讨论过,但从未得到解决。使用ANTS Profiler,我们能够确定内存中持续增长的对象并隔离出问题。
既然问题已经被隔离出来了,有没有办法处理外部API创建的NetworkStream?由于它仍然有一个活动引用,GC.Collect()似乎无法处理它。我们该如何清理悬空引用?有没有一些包装器可以强制清理他们有缺陷的SDK?

我想知道 - 你能否通过反射获取引用? - Daren Thomas
你能否告诉我在哪里找到库中的孤立 NetworkStream?我刚刚查看了 GetEventsMethod,但没有找到 NetworkStream。 - Henning Krause
@HenningKrause 我也尝试了Daren Thomas的方法,但反射需要更深入地研究ExchangeService和SubscriptionBase类的内部,而我选择跳过。目前,我已经暂时遵循Salvatore的#1,并向微软开了一个工单。我们将看看接下来会发生什么... - SliverNinja - MSFT
@SliverNinja 请回复你从微软那里得到的结果。我对此非常感兴趣。 - Henning Krause
1
@HenningKrause 微软从未解决这个问题...他们从未就咨询帮助回复我。无论如何...我们继续使用ANTS来分析我们的组件,发现一个线程中的SQL异常锁定了一个NetworkStream,而EWS会与之冲突。独立地,这些组件工作得很好...但是集成在一起,SQLException将不释放调用线程资源,并创建一个阻塞调用,EWS将在每个服务调用中创建新的NetworkStreams。关键点:始终清理资源-预计会发生故障。 - SliverNinja - MSFT
2个回答

6

无法强制垃圾回收释放引用对象的内存!

首先,我建议您联系微软本身以获取有关此错误的帮助。

其次,您是在谈论“处理”还是仅释放内存?它们是完全不同的东西。(IDisposable模式、终结器)。

第三,您可以取消引用引用这些对象的对象吗?

第四,可能的解决方案之一是使用反编译器反编译导致问题的代码,了解到达保留引用对象的字段的方法,在您的代码中使用反射访问私有字段并将其设置为null。这是一个非常肮脏的技巧,但如果您没有其他方式,这是我能想到的唯一方法。只有在无法采取其他方式时才这样做。


你在第4行的“脏”代码即使字段不是静态的也能工作。这假设存在某个对象,它不应该被“取消引用”,但它(可能间接地)保持有问题的对象处于活动状态。 - svick
当然,这种方法在所有情况下都有效,但如果您只是想取消引用一个没有取消引用其他对象的对象,并且您可以这样做,我建议您当然可以这样做,而不需要任何不正当手段。 - Salvatore Previti

0

最简单的方法是将与SDK接口的部分运行在自己的AppDomain中,完成后卸载该AppDomain。这将导致在AppDomain中分配的所有内存被释放。

但是,您需要在项目中添加一些工作,因为您只能与标记为MarshalByRef对象或标记为serilizableAppDomain进行交换。

这还将允许您监视AppDomain消耗的内存量。因此,您可以创建自己的AppDomain,在其中运行有缺陷的SDK,如果它达到特定的内存消耗限制,则可以卸载它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接