在C#中,我可以阻止从终结器对对象进行垃圾收集吗?

在C#中,我可以阻止从终结器对对象进行垃圾收集吗?,c#,.net,C#,.net,或者,如果达到最终确定方法,是否已经太晚了 基本上,我正在创建一些代码来登录MySql数据库。每个日志条目由一个对象表示并存储在队列中,直到在批插入/更新中将其刷新到数据库。我认为每当我想写一个条目时,在堆上创建一个新对象是低效的(特别是因为我可能想在性能敏感区域写一两个条目)。我的解决方案是创建一个对象池并重用它们 基本上,我不想通过让.Net垃圾收集器告诉我什么时候不再需要某个对象并可以将其添加回池中来重新发明轮子。问题是我需要从析构函数中止垃圾收集。可能吗 连接池是一项功能,实际上任何主要

或者,如果达到最终确定方法,是否已经太晚了

基本上,我正在创建一些代码来登录MySql数据库。每个日志条目由一个对象表示并存储在队列中,直到在批插入/更新中将其刷新到数据库。我认为每当我想写一个条目时,在堆上创建一个新对象是低效的(特别是因为我可能想在性能敏感区域写一两个条目)。我的解决方案是创建一个对象池并重用它们


基本上,我不想通过让.Net垃圾收集器告诉我什么时候不再需要某个对象并可以将其添加回池中来重新发明轮子。问题是我需要从析构函数中止垃圾收集。可能吗

连接池是一项功能,实际上任何主要的DB连接实现都将在本机上支持,因此没有理由手动处理此功能。您可以简单地为每个操作创建一个新连接,并且知道在幕后连接实际上是池连接

要回答你提出的字面问题,是的。您可以确保对象在最终确定后不会进行GCD。只需从某个“活动”位置创建对它的引用即可

但这真是个坏主意。看看这个例子:

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();
}
这将打印出:

定稿

你好,世界


所以在这里,我们有一个最终确定的对象,然后我们稍后访问它。但问题是,该对象已标记为“已完成”。当GC再次命中它时,它第二次没有完成。

您可以在析构函数中重新注册以完成,如下所示:

~YourClass()
{
   System.GC.ReRegisterForFinalize(this);
}
从那以后,你可能想要一些参考资料,这样就不会再定稿了,但这是一种方法


可以吗?可以。
你应该吗?不,这几乎肯定是个糟糕的主意

开发人员应该记住的一般规则如下:

如果你发现自己在写一个终结器,你可能做错了什么

成熟的托管虚拟机(如CLR或JVM)使用的内存分配器速度非常快。在这些系统中,减慢垃圾收集器速度的一个因素是使用定制的终结器。为了优化运行时,您实际上放弃了一个非常快的操作,而选择了一个更慢的操作。此外,“使一个物体复活”的语义很难理解和推理

在考虑使用终结器之前,应了解以下文章中的所有内容。


是的,你可以。抢夺:要详细说明吗?为什么不重用对象,甚至从不取消引用它们?我不明白你为什么要破坏垃圾收集器。你说的“中止垃圾收集”是什么意思?您的意思是不希望GC调用对象终结器吗?为什么不将池拆分为两个组呢。未使用的对象和当前正在使用的对象。为每个对象事件指定保存池的时间。这就控制了它进入哪一组。@MathewFoscarini我一开始就是这么做的,但不幸的是,我不得不成为一个成绩优异的人,我引入了一个打破这种方法的功能。这是一个高度多线程的应用程序(这就是为什么我要通过MySql进行日志记录),因此我想找到一种方法,使日志条目可以逻辑排列,以便于搜索。我制作了一个功能,其中每个日志条目都有一个父条目,每个父条目跟踪它有多少子条目。这意味着,即使在将日志条目刷新到数据库之后,在其所有子项都被刷新之前,它也不可重用。我想Hi-jacking GC是最简单的方法我不认为他说的是db连接。但是日志条目对象。@MathewFoscarini
“我正在创建一些代码来登录MySql数据库”
。他真正想要的是一个DB连接。即使他在技术上试图将日志对象合二为一,显然,日志对象的“昂贵”部分是DB连接;这就是他试图重复使用的内容。好吧,MySql连接器SDK明确表示不要缓存db连接,因为连接器已经为您这样做了。否。我在这里试图避免的开销是在堆上分配日志对象。在大多数情况下,这会让人毛骨悚然,但我正在制作一个实时游戏服务器,所以应该让人毛骨悚然。@user1379635在这种情况下,不这样做几乎肯定会更好。除非创建/处置池对象非常耗时,否则您自己尝试池对象几乎总是会损害性能。在内存中分配对象只需要很少的时间,如果对象的生命周期很短,它们只会给GC增加很少的开销。实际上,在任何实现中,如果没有额外昂贵的对象初始化,则池项目的开销都会更高。这是行不通的。文档说明:“请求系统为先前已调用SuppressFinalize的指定对象调用终结器”。如果第一次调用SuppressFinalize(),则永远不会调用终结器。即使是msdn的例子也不起作用。