为什么我的析构函数被调用?
-
08-07-2019 - |
题
我有一些类通过 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的一些特征 析构函数:
- 析构函数不能在结构中定义。它们仅与类一起使用。
- 一个类只能有一个析构函数。
- 析构函数不能被继承或重载。
- 析构函数 不能被调用. 。他们是 自动调用.
- 析构函数不接受修饰符或具有参数。
所以你的情况发生的是这样的(用两个词来说):
- A 类是垃圾收集。
- 结果1:_粒子字段获得 GC-d。
- 结果2:字典中的条目变为无根(可用于垃圾收集)。
- 结果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
构造函数和终结器中的内容。确保实例化的数量符合您的预期。