C# 如何使JIT将堆栈变量扩展到作用域的末尾(GC太快)
我们正在处理.Net程序中GC太快的问题。 因为我们使用具有本机资源的类,并且不调用GC.KeepAlive(),所以GC在本机访问结束之前收集对象。结果程序崩溃了。 我们的问题正是这里描述的: 像这样:C# 如何使JIT将堆栈变量扩展到作用域的末尾(GC太快),c#,.net,garbage-collection,jit,C#,.net,Garbage Collection,Jit,我们正在处理.Net程序中GC太快的问题。 因为我们使用具有本机资源的类,并且不调用GC.KeepAlive(),所以GC在本机访问结束之前收集对象。结果程序崩溃了。 我们的问题正是这里描述的: 像这样: { var img = new ImageWithNativePtr(); IntPtr p = img.GetData(); // DANGER! ProcessData(p); } 要点是:JIT生成的信息显示GC在GetData()运行时没有使用img。如果GC线
{ var img = new ImageWithNativePtr();
IntPtr p = img.GetData();
// DANGER!
ProcessData(p);
}
要点是:JIT生成的信息显示GC在GetData()运行时没有使用img。如果GC线程在正确的时间出现,它将收集img,程序将崩溃。可以通过添加GC.KeepAlive(img)来解决这个问题;
不幸的是,已经编写了太多的代码(在太多的地方),无法轻松地纠正这个问题
因此:例如,是否有一个属性(即ImageWithNativePtr)使JIT的行为类似于调试构建?在调试版本中,变量img将保持有效,直到作用域结束(}),而在发布版本中,它会在注释危险处失去有效性。据我所知,无法根据方法引用的类型控制jitter的行为。您可能能够为方法本身赋予属性,但这无法满足您的要求。既然如此,你应该咬紧牙关重写代码
GC.KeepAlive
是一个选项。另一种方法是让GetData
返回一个安全句柄,该句柄将包含对对象的引用,并让ProcessData
接受句柄而不是IntPtr
——无论如何,这是一种好的做法。然后,GC将保留安全句柄,直到方法返回。如果您的大多数代码都具有var
而不是代码片段中的IntPtr
,那么您甚至可以不修改每个方法而逃脱惩罚。您有一些选择
图像上使用NativePtr
类实现IDisposable
,因为它可以编译为尝试{…}最后{object.Dispose()}
,如果您使用更新代码,则该对象将保持活动状态。您可以通过安装CodeRush之类的软件(即使免费软件也支持这一功能)来减轻这样做的痛苦,它支持使用
块创建
CLR没有为这个功能内置任何东西。我相信你可以通过一个实现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.
}
我相信
GC.KeepAlive
是您在这里的唯一选择。您的非托管资源不需要某种处理吗?依赖于愚蠢实现的代码被破坏了。这就是为什么存在SafeHandle类。你要找的创可贴很快就会被撕掉。用正确的方法解决这个问题。图像对象的Dispose/Finalizer释放memroy-因此应用程序崩溃。这不是我的设计-我只是需要修复它。不幸的是,存在诸如共享对象等缺陷。如果无法使用安全句柄/专用对象,则最具表现力的语法(而不是KeepAlive)是使ImageWithNativePtr
实现IDisposable
并使用(var img=new ImageWithNativePtr()){…}将代码包装到中,但这需要更多的代码更改。顺便说一句,整个带有NativePTR的图像可以从SafeHandle
中派生出来。IDisposeable策略当然是经过深思熟虑的,但这需要大量的代码更改。目前唯一需要坚持的还是说明的范围。但是,正如我们所知,GC做得更快。好主意——尽管我将把图像作为构造函数参数。