Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使JIT将堆栈变量扩展到作用域的末尾(GC太快)_C#_.net_Garbage Collection_Jit - Fatal编程技术网

C# 如何使JIT将堆栈变量扩展到作用域的末尾(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线

我们正在处理.Net程序中GC太快的问题。 因为我们使用具有本机资源的类,并且不调用GC.KeepAlive(),所以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之类的软件(即使免费软件也支持这一功能)来减轻这样做的痛苦,它支持使用
    块创建
  • (更简单、不正确、更复杂的构建)-使用或Mono.Cecil并创建自己的属性。通常,此属性会导致将GC.KeepAlive()插入到这些方法中

  • 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做得更快。好主意——尽管我将把图像作为构造函数参数。