我的一位同事宣称代表们总是固定在.net的堆中。我似乎无法找到关于这些信息是否属实的任何权威来源。
是真的吗?
答案 0 :(得分:4)
这根本不是真的。代表们没有固定在.Net中。
当代理用作PInvoke函数的参数时,代理就像它们被固定一样。 CLR分配一个本机thunk,它包含对委托的引用。但是这个引用并没有固定委托,也没有作为对象的强引用。
请注意,固定对象不是免费的。它实际上会给GC带来相当大的成本。小剂量这样很好,但是每个.Net代表被固定可能会对性能产生非常明显的影响
答案 1 :(得分:4)
委托本身没有固定,可以由GC自由移动。但是,这并不一定意味着您需要固定它。
在JIT时,生成的非托管代码以及在使用非托管函数指针调用代理代码时实际使用的代码将不会被移动。 Chris Brumme(CLR团队)explained this in detail on his blog(这里的关键句是此存根存在于GC堆外的固定内存中。):
同样,托管代理可以被编组为非托管代码,它们作为非托管函数指针公开。对这些指针的调用将执行非托管到托管转换;呼召惯例的变化;进入正确的AppDomain;和任何必要的论证编组。显然,非托管函数指针必须引用固定地址。如果GC重新安置那将是一场灾难!这导致许多应用程序为委托创建固定句柄。这完全没必要。非托管函数指针实际上是指我们动态生成以执行转换的本机代码存根。封送处理。此存根存在于GC堆外部的固定内存中。
但是,应用程序负责以某种方式延长委托的生命周期,直到不再从非托管代码调用。本机代码存根的生命周期与委托的生命周期直接相关。收集委托后,通过非托管函数指针的后续调用将崩溃或以其他方式破坏该过程。在我们最近的版本中,我们添加了一个客户调试探针,它允许您在代码中干净地检测到这一点 - 这很常见。如果您在开发过程中尚未开始使用Customer Debug Probes,请查看!
所以你的corworker技术上不正确 - 委托可以移动,而不是固定。但是,同事在精神上是“正确的” - 如果您使用非托管函数指针调用它,则不一定需要固定委托,尽管您确实需要保证代表的生命周期。