重复使用对象的实例与每次更新创建新对象的区别

7
重复使用对象实例和每次交换缓冲区时创建新实例之间的差异和陷阱是什么?
背景:
这是我的一个游戏引擎项目。
我正在编写一个TripleBuffer,在其中我有每个对象的三个版本:旧版本、当前版本和未来版本。通过从当前版本读取状态并对未来版本应用更改来对这些对象进行更改。在对所有对象进行更改后(如适用),将交换缓冲区:未来对象变为当前对象,当前对象变为旧对象,旧对象要么被放弃并通过迭代当前对象来分配新对象,要么成为现在的未来对象,并通过迭代当前对象更新(或覆盖)它们的值。
解释:
“重复使用”:用新值覆盖旧实例的值,有效地改变实例的状态
“新建/克隆”:使用旧实例的数据创建一个新实例,并对其进行更改
用例:
假设有1000个对象以30Hz交换,这意味着它们需要每秒重新创建30次,方法是克隆现在的当前对象或重用现在过时的上一个旧对象(覆盖它们的所有状态)。
它们的复杂性可以从5个属性到数百个属性不等,并且始终具有至少2级深度。
(至少2级深度=缓冲对象本身仅包含构成它们的其他唯一对象的映射)
重新创建和重复使用都需要迭代当前对象及其组件(短于:依次组成它们的对象)。
进一步考虑:
在引擎的其他部分中,将有事件触发和其他魔法,这些事件将使用对象的即时快照进行工作。因此,重新创建或重复使用的决定将导致以下情况之一:
重新创建意味着我可以安全地传递对象的引用,因为该对象将在成为“当前对象”时变为不可变。
重复使用意味着我必须创建当前对象或我进一步需要的任何部分的副本,因为我不能保证事件(或其他)将在对象被重复使用之前处理

你一次处理多少个对象?创建它们的成本有多高(例如,它们有多少属性,构造函数初始化需要多长时间,它们将处于“有效”状态多长时间——即您更新它们的频率)?通常,我建议避免“重用”,除非它们是不可变的……因为你可能会面临数据损坏的风险。你在尝试制定垃圾回收策略吗? - Sendi_t
编写“高效执行”的代码通常是一件好事;但请记住:除非您在谈论时间关键的高性能计算应用程序……不要担心性能。相反,尝试编写易于理解和维护的代码。在这方面,如果对象是不可变的(它们的内部状态在创建后是“固定的”),例如,您可以避免许多有关线程安全的问题。因此,我倾向于避免“重用”任何东西,除非您在这里谈论数百万个对象。 - GhostCat
2个回答

10

除非你有很好的理由,否则请丢弃旧对象并创建新对象。

这将减少各种错误的发生机会。例如,如果在其他地方引用了旧对象,则重复使用它可能会产生不良副作用。从概念上讲,丢弃和创建新对象更加清晰,并且可能使代码更易于阅读、调试和维护。

通常情况下,垃圾回收器也足够聪明,可以使丢弃和重新创建对象的成本不那么昂贵。

在这种情况下,我会编写最清晰、最直接的代码,这意味着每当需要时创建一个新对象。然后我会测试它,看看是否是性能瓶颈,只有在是的情况下,我才会考虑优化。换句话说,我会尽量避免过早优化


这里的一个问题(我同意关于过早优化的观点)是,这个决定基本上决定了代码库的其余部分将如何构建;将添加一个示例/用例。 - dot_Sp0T

1
在Graphics中使用缓冲区是为了避免在更新屏幕时逐像素地"绘制"到屏幕上。相反,你需要绘制到缓冲区,然后可以一次性交换整个图像。
我猜你使用缓冲区的原因也类似。你不希望在处理它们时用新的更新对象修改"当前"对象,因为这会破坏当前对象的"图像"。
重复使用的优点:
- 消耗更少的内存,需要更少的垃圾回收 - 只需要更新已更改的对象
重新创建的优点:
- 每个对象都必须被创建 - 更简单和清晰
你最终的决定将基于性能与清晰度之间的平衡。重新创建所有对象的成本有多高?比较每个对象并仅构建所需的对象是否更便宜?
即使比较对象或跟踪哪些对象已更改更便宜,出于更简单的考虑,创造新的对象可能值得付出代价,这正是@DaphnaShezaf's answer所讨论的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接