或者,如果达到最终化方法,它是否已经迟到了?
基本上我正在创建一些代码来登录MySql数据库.每个日志条目由一个对象表示并存储在队列中,直到它在批量插入/更新中刷新到数据库.我想每次我想写一个条目时在堆上创建一个新对象是低效的(特别是因为我可能想在性能敏感区域写一两个条目).我的解决方案是创建一个对象池并重用它们.
基本上我试图不通过让.Net垃圾收集器让我知道何时不再需要一个对象并且可以将其添加回池中来重新发明轮子.问题是我需要从析构函数中止垃圾收集.那可能吗?
你能?是.
你应该?不,这几乎肯定是一个糟糕的主意.
C#开发人员应该记住的一般规则如下:
如果你发现自己写了一个终结器,你可能做错了什么.
完善的托管VM(例如CLR或JVM)使用的内存分配器非常快.在这些系统中减慢垃圾收集器的一个原因是使用定制的终结器.为了优化运行时,您实际上放弃了非常快速的操作,而采用了更慢的操作.此外,"使物体恢复生机"的语义难以理解和推理.
在考虑使用终结器之前,您应该了解以下文章中的所有内容.
连接池是几乎所有主要数据库连接实现都已原生支持的功能,因此没有理由手动处理此问题。您将能够简单地为每个操作创建一个新连接,并知道在幕后连接实际上将被池化。
回答你问的字面问题,是的。您可以确保对象在终结后不会被 GC。您只需从某个“实时”位置创建对它的引用即可做到这一点。
但这确实是一个坏主意。看一下这个例子:
public class Foo
{
public string Data;
public static Foo instance = null;
~Foo()
{
Console.WriteLine("Finalized");
instance = this;
}
}
public static void Bar()
{
new Foo() { Data = "Hello World" };
}
static void Main(string[] args)
{
Bar();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Foo.instance.Data);
Foo.instance = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
Run Code Online (Sandbox Code Playgroud)
这将打印出:
最终确定
你好世界
所以在这里我们最终确定了一个对象,然后我们稍后访问它。然而问题是该对象已被标记为“最终确定”。当它最终再次被GC命中时,它并没有第二次被最终确定。