在这种情况下不调用GC.KeepAlive()是否安全?

c#

假设我们在发布版本中运行了以下代码:

class SomeClass
{
  // This field is initialized somewhere in the constructor (not shown here).
  public SomeOtherClass Value;

  ...
}

class SomeOtherClass {
  ...
  public void Call() {
     ...
  }
}
...

static void Main()
{
  SomeClass obj = new SomeClass();
  SomeOtherMethod(obj.Value);
  ...
}

static void SomeOtherMethod(SomeOtherClass value) {
  ... // do sth else first
  value.Call();   // value is a reference that points to `obj.Value` object in heap
}

我一直看到这样的代码,当时我并不熟悉 GC 的工作原理。但现在我知道垃圾收集可能会在运行时检索 obj.Value 之后收集 obj,即在 SomeOtherMethod() 被调用之前。所以有可能(虽然不太可能,但仍然有可能)在SomeOtherMethod执行和操作obj.Value参数之前,obj已经被标记为不可达(因此它的成员Value也被标记为不可达)并被 GC 收集并回收它们的内存,所以它是非法SomeOtherMethod访问Value

所以我认为一个解决方案是添加GC.KeepAlive(obj)GC.KeepAlive(obj.Value)作为:

void MyMethod()
{
  SomeClass obj = new SomeClass();
  SomeOtherMethod(obj.Value);
  ...
  GC.KeepAlive(obj);   //  or GC.KeepAlive(obj.Value);
}

但是我没有看到很多人(高级开发人员)这样做,并且代码始终正确运行而不会引发任何异常。那么我的理解是错误的还是 CLR 对此有解决方法?

回答

obj.Value被读取时,它的(可能是一个引用,或者一个基元/结构)被复制(到哪里无关紧要;注意,在引用的情况下,它只是被复制的引用,而不是它所指的对象)。在这一点上,是否被收集并不重要obj- 值的副本是独立的。

请注意,如果您使用 ref-return 属性或带有 的裸字段SomeOtherMethod(ref obj.Value),则情况略有不同,但在这种情况下:我们仍然知道 GC 可以遵循托管指针(也称为ref),并且如有必要,这将使对象保持活动状态

所以不,你不需要GC.KeepAlive. 您需要 的时间GC.KeepAlive非常小众和奇特(通常涉及终结器和数据之间的间接(非参考)关系);在大多数日常场景中:GC 无需您的输入即可执行您想要的操作。

  • @amjad to use an example: you ask me for Fred's phone number; I look it up on my phone, and tell it you; now **my** phone gets lost/stolen/broken/recalled/whatever. This doesn't affect you: you still have Fred's phone number - the copy scribbled on the back of an envelope (or whatever) is not impacted *even slightly* by the fact that my phone is gone

以上是在这种情况下不调用GC.KeepAlive()是否安全?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>