如何评价自定义内存分配器的质量

How to evaluate the quality of custom memory allocator?

本文关键字:分配器 内存 自定义 何评价 评价      更新时间:2023-10-16

在评估内存分配时应该检查哪些特征?

分配和取消分配的性能?简单的压力测试就足够了吗?如何检查分配质量?

例如,我找到了Oracle的malloc测试,但这只是Oracle对问题的看法。这个测试只面向多线程性能。

人们通常如何检查他们的分配器?

只是把更多的注意力放在"如何"上,而不是其他答案似乎要处理的"是什么"上。我是这样做的。

第一步-使比较方法成为可能

确定你看重什么品质。列一个清单,优先排序,最后,制定一个价值函数。

也就是说,在您的视图/案例中,找出哪些度量是最有用的质量指示器。一些好的测量方法可以是分配内存块的平均时间,应用程序的总运行时间(如果适用),平均帧速率,总或平均内存消耗……这完全取决于你想达到什么目标。

然后,创建一个函数,给定测试运行中的这些测量值,该函数将为您提供一个可用于质量度量的值。最简单的情况是简单地为每个测量值确定一个权重因子。这些权重因素应该体现每个度量的重要性,并且如果它们使用不同的单位(例如用纳秒表示平均分配时间,用字节表示平均内存消耗),则应该尝试缩放它们以进行公平比较。

第二步-设备测试场景

这应该尽可能接近实际情况。最好的是您想要使用内存分配器的实际代码,并添加用于计算值函数所需的所有测量的代码。

第三步-测试

编写一堆不同的分配器,并相互测试它们,以及默认的或没有任何分配器(如果适用)。测量所有结果,计算每个结果的值函数,并根据结果对它们进行排序。请记住在执行性能度量时需要考虑的所有不同因素。

第四步-求值并重复

看看不同的解决方案是如何相互比较的。运用一些批判性思维。这些结果是否与您在测试期间对每个分配器的质量的体验相一致?如果结果与你所看到的不相符。

例如,如果一个看起来非常快,总运行时间比其他的少半分钟,得到一个平庸的分数。那是时候审视一下你的方法了。也许你的测量有问题?或者也许你需要重新评估你选择的价值函数……重复步骤1到步骤4,直到结果清晰,并且看起来与您测试它们的实际经验一致。

通常,内存分配器的性能是关于在堆中查找和创建内存块的速度,这取决于被操作的内存块的大小。而且(最近),它在多线程分配的情况下是如何表现的。您可以在以下列表中找到有趣的研究和基准测试:

  • ptmalloc -一个多线程malloc实现
  • 无锁内存分配器的基准测试
  • Linux系统库中的动态内存分配器实现基于FreeBSD的可伸缩并发malloc(3)实现
  • …可能还有很多人…

我想我的答案不是天才,但是——看情况。

如果你正在编写自定义内存分配器,你可能知道它的特性是什么。如。如果你想让分配器允许你快速分配很多小对象,你真的不关心内存使用开销,你可能应该有不同的测试,然后当你为大对象创建分配器,你想节省尽可能多的内存,即使CPU时间的成本。

压力测试总是好的,因为它可以帮助您找到一些竞争条件,并检查您的分配器是否没有错误,但性能测试取决于您想要实现的目标。

在优化/分析系统中的动态内存分配机制时,应该考虑以下指标:

  • 实现开销 -保持分配的内部数据结构的运行需要消耗多少内存。此外,如果这些结构随着时间的推移而增长或预先分配一次(这两种方法都有优缺点,而且都是有效的)。
  • 操作效率 -分配/释放内存块所需的时间。这里的分配通常是一个挑战,因为它几乎从来都不是一个常数时间,并且取决于先前分配的内存块的特征。释放块看起来很简单,但如果与内存碎片清理结合使用,则值得进一步注意(此处不涉及)。
  • 线程安全与分配本身关系不大,更多地与在系统中使用某种解决方案的决定有关。基本上,如果你没有线程,没有什么好担心的。如果你有线程,确保你的分配在工作时不会被中断。
  • 内存碎片 -实际分配的内存布局。这里出现了两个完全矛盾的需求—在缓冲区中找到正确的位置后立即进行分配,或者确保尽可能少地造成碎片。前者更快,而后者更资源友好(也可能更慢)。
  • 垃圾收集——这是一个单独的主题,也是一个独立的研究领域,提到它只是为了完整。重要的是要理解,即使您不打算太频繁地释放已分配的内存,GC仍然可以用于帮助分析已分配的内存,为下一次有效的内存分配准备内部数据结构。空闲CPU时间是执行这个家务任务的最佳时间,这是有争议的。然而,这个话题超出了这个问题的范围。