如果被引用的对象被删除,引用变量会发生什么?

4

假设我有以下类...

Class1
{
  private ArrayList myList;

  private Class1
  {
    // Here fill myList with a bunch of Foo objects.
  }

  public ArrayList GetList()
  {
    return myList;
  }
}

然后在另一个类中,您有以下代码...
Class1 myClass = new Class1();
Foo myFavoriteFoo = myClass.GetList()[0] As Foo;

现在,myFavoriteFoo实际上是对Class1中arraylist中存在的Foo的引用。如果Class1内部的某些东西删除了该特定的Foo或处理掉它,会发生什么?myFavoriteFoo会立即= null吗?我猜如果我尝试访问Foo.SomeMethod(),我只会得到一个异常,如“对象引用未设置为对象的实例”...

6个回答

3
答案是不可能发生。
dotNet提供类型安全:引用始终指向有效实例或为null,没有其他选项。这就是为什么在dotNet中没有手动内存管理(没有delete)的原因。
因此,如果您的代码在某个地方持有对象的引用,则该引用会阻止垃圾回收。
而Dispose()是另外一件事情,它与对象占用的内存无关。Dispose()是(非托管)资源的清除操作,通常对象将其内部状态设置为IsDisposed=true(“无效”)。
所以你可以关闭(== Dispose)一个FileStream。然后你仍然拥有这个对象,只是当你尝试使用它时会抛出异常。

实际上,如果对于非托管资源进行了适当的实现,那么当对象不再使用时,垃圾回收器会自动释放分配给托管对象的内存。请注意,一个人可以实现 IDisposable 接口,但实际上可能并没有使用非托管资源。 - TheCloudlessSky
@TheCloud:GC 自动释放 所有 托管对象,与非托管资源无关。 - H H

1

只要还有引用指向它们,引用对象就不会被删除(虽然有少数例外情况你不必担心)。当原始引用超出作用域时,其它引用仍将指向该对象,并且该对象将保持存活状态。在放弃第二个引用后(通过将其设置为null、分配一个不同的值或使其超出作用域),GC可能会收集它(但不能保证立即这样做)。


0
如果对象在myFavoriteFoo引用它之后被设置为null,则myFavoriteFoo仍然保留引用。如果Foo正确实现了IDisposable,那么在调用Dispose()之后尝试访问它将会导致异常。

0

首先,您需要了解引用类型。如果您不懒惰的话,可以尝试自己编写代码,以查看会发生什么。

真正的行为是,如果有人从列表中删除对象,则并不意味着该对象从内存中删除。垃圾回收器检查对象是否有引用,而在您的情况下,myFavoriteFoo保留引用,因此GC不会删除对象。

在处理处置时,在C#中没有办法强制手动删除对象,即使您调用dispose或析构函数,也会通过垃圾回收器检查对象,只有当它具有0个引用时,才会删除对象。

这适用于常规引用。在.Net中还有一个类WeakReference,它覆盖了常规引用的规则。


0

Class1本身不拥有ArrayList,它只是持有对它的引用。无论是myFavoriteFoo还是myClass.myList都是对ArrayList的引用

因此,该类只能将其自己的引用设置为null。但这并不会删除ArrayList,只是表示对它的引用减少了一个。

但只要至少有一个引用,ArrayList 就不会被删除。因此,您描述的情况永远不会发生。


0

myFavoriteFoo是指向对象的另一个引用(除了数组中的一个)。只要引用存在,对象就不会被垃圾回收。因此,在Class1中从数组中删除元素不会影响myFavoriteFoo引用 - 它仍然存在。另一方面,如果在Class1中通过dispose/close调用处理对象,则如果尝试使用其方法可能会出现错误 - 错误消息可能是该对象已被处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接