GC.KeepAlive与使用

在他关于防止应用程序的多个实例的文章中 ,Michael Covington提出了以下代码:

static void Main() // args are OK here, of course { bool ok; m = new System.Threading.Mutex(true, "YourNameHere", out ok); if (! ok) { MessageBox.Show("Another instance is already running."); return; } Application.Run(new Form1()); // or whatever was there GC.KeepAlive(m); // important! } 

他解释说,GC.KeepAlive(m)是防止垃圾收集器尽早收集互斥锁所必需的,因为没有额外的引用。

我的问题:将使用互斥锁包装做同样的事情吗? 也就是说,以下是否也会阻止GC从我身下拉出地毯?

 static void Main() // args are OK here, of course { bool ok; using (var m = new System.Threading.Mutex(true, "YourNameHere", out ok)) { if (! ok) { MessageBox.Show("Another instance is already running."); return; } Application.Run(new Form1()); // or whatever was there } } 

我的直觉反应是使用将起作用,因为使用(应该是)相当于:

 Mutex m = new System.Threading.Mutex(true, "YourNameHere", out ok); try { // do stuff here } finally { m.Close(); } 

我认为m.Close()足以向JIT编译器发出信号,告知还有另一个引用,从而防止过早的垃圾收集。

using语句中包装互斥锁确实会阻止它被垃圾收集,但也会在最后处理它(它调用Dispose ,而不是Close )(而GC.KeepAlive显然不会)。

如果该方法的结尾真的将成为该过程的结束,我不相信它可能会使您使用任何实际差异 – 我更喜欢using处理任何实现IDisposable的一般原则的using语句。

如果在进程退出时没有处理互斥锁,我怀疑它的终结器会处理它 – 只要其他终结器不会超出终止线程超过其超时。

如果终结器没有处理它,我不知道Windows本身是否会注意到该进程不再可能拥有互斥锁,因为它(进程)不再存在。 我怀疑它会,但你必须检查详细的Win32文档,以确定。

在这种情况下使用using似乎比使用GC.KeepAlive更合适。 只要应用程序正在运行,您不仅希望保持Mutex处于活动状态,还希望它在退出主循环后立即消失。

如果您只是将Mutex挂起而不进行处理,则可能需要一段时间才能完成,具体取决于应用程序关闭时要执行的清理工作量。

我认为KeepAlive与命名的Mutex一起使用的原因是为了确保它不是早期的垃圾收集。 C#using / Dispose模式不是为了保护它。 当在范围内不再使用对象引用时,运行时可以在范围结束之前收集它。 这是一个优化。