我们在.Net程序中处理GC太快了。 因为我们使用具有本机资源的类而我们不调用GC.KeepAlive(),所以GC在Native访问结束之前收集对象。结果程序崩溃了。 我们遇到了如下所述的问题:
Does the .NET garbage collector perform predictive analysis of code?
像这样:
{ var img = new ImageWithNativePtr();
IntPtr p = img.GetData();
// DANGER!
ProcessData(p);
}
重点是:JIT生成的信息显示GC在运行GetData()时未使用img。如果GC-Thread在合适的时间出现,它会收集img并且程序崩溃。可以通过附加GC.KeepAlive(img)来解决这个问题。 不幸的是,已经写了太多代码(在太多的地方)来轻松纠正这个问题。
因此:例如是否有一个属性(即ImageWithNativePtr)使JIT在Debug构建中表现得像?在Debug构建中,变量img将保持有效,直到scope(})结束,而在Release中,它会在注释DANGER中失去有效性。
答案 0 :(得分:2)
据我所知,无法根据方法引用的类型来控制抖动的行为。您可以将方法本身归属,但这不会填满您的订单。既然如此,你应该咬紧牙关并重写代码。 GC.KeepAlive
是一种选择。另一种方法是让GetData
返回一个安全句柄,该句柄将包含对象的引用,并且ProcessData
接受句柄而不是IntPtr
- 这无论如何都是好的做法。然后GC将保持安全句柄,直到方法返回。如果您的代码片段中的大多数代码都有var
而不是IntPtr
,那么您甚至可以在不修改每种方法的情况下离开。
答案 1 :(得分:1)
您有几个选择。
IDisposable
类上实施ImageWithNativePtr
,因为它会向下编译为try { ... } finally { object.Dispose() }
,如果您使用{{{{}}更新代码,这将使对象保持活动状态1}}秒。你可以通过安装像CodeRush这样的东西来缓解这样做的痛苦(即使是免费的Xpress支持这个) - 它支持创建using
块。CLR没有为此功能内置任何内容。
答案 2 :(得分:0)
我相信您可以使用实现IDispose的容器和using语句来模拟您想要的内容。 using语句允许定义范围,您可以在其中放置任何需要在该范围内保持活动的内容。如果您无法控制ImageWithNativePtr的实现,这可能是一种有用的机制。
要处理的东西的容器是一个有用的习语。特别是当你真的应该处理某些东西时......可能是图像的情况。
using(var keepAliveContainer = new KeepAliveContainer())
{
var img = new ImageWithNativePtr();
keepAliveContainer.Add(img);
IntPtr p = img.GetData();
ProcessData(p);
// anything added to the container is still referenced here.
}