C# 垃圾回收 - > C++删除

C# Garbage Collection -> to C++ delete

本文关键字:gt C++ 删除      更新时间:2023-10-16

我正在将一个C#项目转换为C++,并有一个关于在使用后删除对象的问题。在C#中,GC当然负责删除对象,但在C++中,必须使用delete关键字显式删除对象。

我的问题是,在整个方法中只遵循每个对象的用法,然后在超出范围时立即删除它(即方法结束/重新分配),可以吗?

不过我知道GC在删除之前会等待一定大小的垃圾(~1MB);它这样做是因为在使用delete时会产生开销吗?

由于这是一个我正在创建的游戏,每秒可能会有很多对象被创建和删除,所以最好跟踪超出范围的指针,一旦大小达到1MB,就删除指针吗?

(附带说明:稍后当游戏优化时,对象将在启动时加载一次,因此在游戏过程中没有太多可删除的内容)

您的问题是在C++中使用指针。

这是一个你必须解决的基本问题,然后你所有的问题都会消失。碰巧的是,我受够了这个大趋势,所以我制作了一套关于这个问题的演示幻灯片(CC BY,请随意使用)。

看一下幻灯片。虽然它们肯定不是完全严肃的,但基本信息仍然是正确的:不要使用指针但更准确地说,消息应该是:不要使用delete

在你的特殊情况下,你可能会发现自己有很多长寿命的小物体。这确实是一种现代GC处理得很好的情况,而引用计数智能指针(shared_ptr)处理得效率较低。如果(且仅当!)这成为性能问题,请考虑切换到小型对象分配器库。

您应该在C++中尽可能多地使用RAII,这样您就不必在任何时候显式地delete
一旦你通过智能指针和你自己的资源管理类使用RAII,你所做的每一个动态分配都将只存在,直到有任何可能的引用为止,你不必显式管理任何资源。

C#和C++中的内存管理完全不同。您不应该试图在C++中模仿.NET的GC的行为。在.NET中,分配内存是非常快的(基本上是移动指针),而释放内存则是一项繁重的任务。在C++中,由于几个原因,分配内存并不是那么轻,主要是因为必须找到足够大的内存块。当在程序执行过程中多次分配和释放不同大小的内存块时,堆可能会变得碎片化,包含许多可用内存的小"洞"。在.NET中,这不会发生,因为GC将压缩堆。不过,在C++中释放内存的速度相当快。

.NET中的最佳实践不一定适用于C++。例如,大多数时候不建议在.NET中池化和重用对象,因为GC会将对象提升到更高的一代。GC最适合使用寿命短的对象。另一方面,C++中的池化对象对于避免堆碎片化非常有用。此外,分配更大的内存块并使用放置新对于许多需要频繁分配和释放的较小对象来说效果很好,就像在游戏中一样。阅读C++中的通用内存管理技术,如RAII或placement-new。

此外,我建议你读《高效C++》和《更有效的C++》这两本书。

好吧,最简单的解决方案可能是在C++例如,Boehm收集器运行良好。尽管如此优点和缺点(但移植最初用C#编写的代码将是在这种情况下,很可能是有利因素大于不利因素的候选人。)

否则,如果您将代码转换为惯用C++,就不应该有许多动态分配的对象需要担心。与C#不同,C++默认情况下具有值语义,并且您的大多数短期对象应该是简单的局部变量,如果返回可能会被复制,但不是动态分配的。在C++中,动态分配通常是仅用于实体对象,其生存期取决于外部事件;例如,Monster是在某个随机时间创建的,具有一定的概率根据游戏状态,并在稍后的某个时间删除对改变游戏状态的事件的反应。在这种情况下当怪物不再是游戏的一部分时,删除该对象。在里面C#,您可能有一个dispose函数或类似的函数,用于这样的对象,因为它们通常具有必须当它们不复存在时执行—比如注销为一个观察者,如果这是你正在使用的模式之一的话。在C++中这类事情通常由析构函数处理,而不是调用dispose,则调用delete对象。

在C#中使用引用的每个实例中替换shared_ptr将在转换代码时以可能最低的工作量获得最接近的近似值。

然而,您特别提到了通过方法跟踪对象的使用并在最后删除-更好的方法是根本不新建对象,而是简单地在堆栈上内联/实例化它。事实上,如果您采用这种方法,即使对于引入了新的复制语义的返回对象,这也将成为处理返回对象的有效方法,因此几乎没有必要在每个场景中都使用指针。

在释放对象时,除了在超出范围时调用delete之外,还有很多事情需要考虑。您必须确保只调用delete一次,并且只调用它一次指向该对象的所有指针都超出了范围。.NET中的垃圾收集器为您处理所有这些。

与C++中的构造最为对应的构造是tr1::shared_ptr<>,它保留一个对对象的引用计数器,并在它降到零时释放。让事情运行起来的第一种方法是将所有C#引用放到C++tr1::shared_ptr<>中。然后,您可以进入那些它是性能瓶颈的地方(只有在使用概要文件验证它是实际的瓶颈之后),并更改为更高效的内存处理。

c++的GC特性在SO中已经讨论了很多

试着通读一遍!!

C++中的垃圾收集