我有一些类通过 IDictionary 实例成员保存对其他类的引用。

就像这样:

class A
{
  private readonly Dictionary<int, B> _particles = new Dictionary<int, B>();
  public void CreateNewB(int someInt)
   {
     var b = new B();
     if (!_particles.ContainsKey(someInt)
         _particles.Add(someInt, b);
   }
}

所以这就是设置,我从来没有从这个字典中删除它们,但由于某种原因,B 类的析构函数时不时地在 GC 运行时被调用,我不明白为什么。

这可能与 Dictionary 类添加新引用的方式有关吗?

固定的:

好的,谢谢大家的回答,我现在对 GC 和解构函数有了很大的了解。

但问题是我自己的,我正在补充 一些整数 除非它不存在并且通过有缺陷的业务逻辑, 一些整数 始终为 1,因此第一次运行时有效,并且解构函数没有被调用。但第二次,“b”实例根本没有添加到列表中,并且在 GC 运行中被清理掉。

再次感谢所有提供帮助的人!

有帮助吗?

解决方案 5

好的,谢谢大家的回答,我现在已经对GC和解构器有了很大的了解。

但是这个问题是我自己的,我只是在它已经存在并且通过有缺陷的业务逻辑时添加someInt,someInt总是1,所以第一次通过它工作并且解构器没有被调用。但第二次,“b”,实例根本没有添加到列表中,并在GC运行中被清理。

我正在回答此事只是为了关闭它:)

其他提示

如果对A类的引用已经死亡,那么你的B级将是GC

我从不将它们从这个词典中删除,但是由于某种原因,B级的驱动器被称为

.NET 中的析构函数与 C++(非托管)中的析构函数不同。
析构函数调用 最终确定 自动方法。

以下是a的一些特征 析构函数:

  • 析构函数不能在结构中定义。它们仅与类一起使用。
  • 一个类只能有一个析构函数。
  • 析构函数不能被继承或重载。
  • 析构函数 不能被调用. 。他们是 自动调用.
  • 析构函数不接受修饰符或具有参数。

所以你的情况发生的是这样的(用两个词来说):

  1. A 类是垃圾收集。
  2. 结果1:_粒子字段获得 GC-d。
  3. 结果2:字典中的条目变为无根(可用于垃圾收集)。
  4. 结果3:字典中的条目(B 类实例)是 GC-d。

这可能与字典类添加新参考有关的方式有关系吗?

不。

听起来你做的事情非常错误。在托管环境中,保持像这样基本上永久存在的引用相当于内存泄漏,除非你真的想要保留这些对象。

这里要记住的另一件事是C#中没有析构函数这样的东西。你所拥有的是终结者,它们是不同的。托管代码很少见,甚至根本不需要编写终结器。这样做的唯一理由是,当您为类型实现IDisposable以包装未被终结器覆盖的非托管资源时。

例如,很多人创建了一个实现IDisposable的类型,并将SqlConnection包装为其数据访问层的一部分。这样,他们可以使用块包装该类型的实例,并确保他们创建的任何SqlConnections都正确处理。但是这种类型需要终结器,因为底层数据库连接已经被SqlConnection类本身的终结器所覆盖。没有 new 非托管资源类型需要担心,只有SqlConnection类型。但是,如果您正在构建一个全新的数据库引擎并为其实现新的.Net数据提供程序,那么您可能希望为您的连接实现终结器。

所以我有以下类型:

type k {
public k() { Console.WriteLine("Hi, I'm a new K!"); }
public ~k() { Console.WriteLine("I'm a dying K!"); }
}

还有一小段代码:

Dictionary<int, k> ks = new Dictionary<int, k);
for(int i=0;i<10;i++) { ks.add(i, new k()); }

你看到~k()被一次调用了?那是什么意思?

我打赌我的钱在其他地方创建了 B 。如果它是一个控制台应用程序,则输出 B 构造函数和终结器中的内容。确保实例化的数量符合您的预期。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top