在C#中,我可以阻止从终结器对对象进行垃圾收集吗?
或者,如果达到最终确定方法,是否已经太晚了 基本上,我正在创建一些代码来登录MySql数据库。每个日志条目由一个对象表示并存储在队列中,直到在批插入/更新中将其刷新到数据库。我认为每当我想写一个条目时,在堆上创建一个新对象是低效的(特别是因为我可能想在性能敏感区域写一两个条目)。我的解决方案是创建一个对象池并重用它们在C#中,我可以阻止从终结器对对象进行垃圾收集吗?,c#,.net,C#,.net,或者,如果达到最终确定方法,是否已经太晚了 基本上,我正在创建一些代码来登录MySql数据库。每个日志条目由一个对象表示并存储在队列中,直到在批插入/更新中将其刷新到数据库。我认为每当我想写一个条目时,在堆上创建一个新对象是低效的(特别是因为我可能想在性能敏感区域写一两个条目)。我的解决方案是创建一个对象池并重用它们 基本上,我不想通过让.Net垃圾收集器告诉我什么时候不再需要某个对象并可以将其添加回池中来重新发明轮子。问题是我需要从析构函数中止垃圾收集。可能吗 连接池是一项功能,实际上任何主要
基本上,我不想通过让.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)使用的内存分配器速度非常快。在这些系统中,减慢垃圾收集器速度的一个因素是使用定制的终结器。为了优化运行时,您实际上放弃了一个非常快的操作,而选择了一个更慢的操作。此外,“使一个物体复活”的语义很难理解和推理
在考虑使用终结器之前,应了解以下文章中的所有内容。
“我正在创建一些代码来登录MySql数据库”
。他真正想要的是一个DB连接。即使他在技术上试图将日志对象合二为一,显然,日志对象的“昂贵”部分是DB连接;这就是他试图重复使用的内容。好吧,MySql连接器SDK明确表示不要缓存db连接,因为连接器已经为您这样做了。否。我在这里试图避免的开销是在堆上分配日志对象。在大多数情况下,这会让人毛骨悚然,但我正在制作一个实时游戏服务器,所以应该让人毛骨悚然。@user1379635在这种情况下,不这样做几乎肯定会更好。除非创建/处置池对象非常耗时,否则您自己尝试池对象几乎总是会损害性能。在内存中分配对象只需要很少的时间,如果对象的生命周期很短,它们只会给GC增加很少的开销。实际上,在任何实现中,如果没有额外昂贵的对象初始化,则池项目的开销都会更高。这是行不通的。文档说明:“请求系统为先前已调用SuppressFinalize的指定对象调用终结器”。如果第一次调用SuppressFinalize(),则永远不会调用终结器。即使是msdn的例子也不起作用。