我需要固定匿名代表吗?

Spe*_*ETC 7 c# winapi interop kernel32 pinning

我从C#应用程序调用CopyFileEx,并将匿名委托传递给LPPROGRESS_ROUTINE参数,以便获取有关文件复制进度的通知.

我的问题是,匿名代表是否需要固定以及为什么(或为什么不).

此外,如果:

  1. CopyFileEx没有阻止.
  2. 如果我传入一个非匿名的代表.

谢谢!

Eri*_*ert 6

代表不需要固定.如果托管对象无法被垃圾收集器移动,则会固定该对象.如果编组信息是正确的,那么编组层将确保传递指向不动的东西的指针.

但是,上面的注释中您建议局部变量可能使委托保持活动,这表明对变量生命周期的误解.我推荐你的规范,其中说明:

局部变量的实际生命周期取决于实现.例如,编译器可能静态地确定块中的局部变量仅用于该块的一小部分.使用此分析,编译器可以生成导致变量存储的生命周期比其包含块短的代码.由本地引用变量引用的存储被回收,而与该本地引用变量的生命周期无关

换句话说,如果你说:

void M()
{
    Foo foo = GetAFoo();
    UnmanagedLibrary.DoSomethingToFoo(foo);
}
Run Code Online (Sandbox Code Playgroud)

然后允许抖动说"你知道,我发现在调用非托管调用之后,没有托管代码再次使用foo;因此我可以在那时从另一个线程中积极地回收该对象的存储".这意味着非托管调用可以在突然在另一个线程上释放时对该对象起作用.

如果Foo有一个析构函数,这尤其令人讨厌.当对象被非托管库使用时,终结代码可能会在另一个线程上运行,而天堂只知道将导致什么样的灾难.

在这种情况下,您需要使用KeepAlive来保持托管对象的活动.不要依赖局部变量; 局部变量具体记录为保证保持活力.

有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx.

  • @SpeksETC:您链接的文章明确指出您的假设是错误的.它说"**但是,应用程序负责以某种方式延长委托的生命周期,直到不再从非托管代码**调用." (2认同)

Ste*_*ary 3

您不需要固定它,但只要复制正在进行,您就需要保持对它的引用。

非托管代码调用的 thunk 被固定,但您必须确保委托没有被垃圾收集 - 因此是引用。

  • @sehe - 否。如果需要,确定变量实际生命周期的机制可能会假定被调用方法中的参数本身将保存对托管对象的引用。如果参数变量在被调用的方法中快速设置为 null(或其他值),则这可能是一个值得的优化,在这种情况下,托管对象没有引用并且可以安全地收集,即使被调用的方法尚未返回。 (3认同)