1

我目前正在开发一个缓存服务器,它本身就使用大量RAM(我正在一个具有大量HTTP流量的服务器上测试它,并且WordPress和一个自定义 Web 应用程序都使用它来缓存内存中的数据) .

服务器显然执行了很多昂贵的 malloc/realloc/free 操作,所以我想知道是否应该使用自定义内存分配器,也许是在开始时预分配一个大“内存池”然后使用它来释放执行 malloc/realloc 时请求大小的“块”,并在调用 free 时将它们标记为已释放。

我走的是正确的道路还是我真的不需要这样的东西?有没有这样的分配器,还是我必须自己编写一个?

重要笔记:

  • 服务器是单线程的(使用多路复用),所以我不需要在多线程应用程序中具有高性能等级的分配器(例如jemalloc,据我了解,它与单线程中的普通 malloc 一样好应用程序...如果我错了,请纠正我)。

  • 在您提出/建议之前,我已经使用Valgrind消除了所有可能的内存泄漏。我只需要优化,而不是修复。

  • 内存碎片是一个问题,所以我也应该使用一种方法来优化它。

  • 使用适当的配置指令,用户可以设置服务器的最大可用内存,这就是我想到预先分配的固定内存池的原因。

  • 我没有性能问题;我开发这个只是为了好玩和好奇。我喜欢学习和尝试新的编程技术。

  • 是的,我使用过 callgrind,而 malloc 是最昂贵的操作之一。

4

1 回答 1

2

既然你说你没有性能问题,你不需要做任何事情。把它放在一边。

你需要一个立足点来获得任何改进,因为malloc它真的很快。我记得几年前在 Mac OS X 上大约有 100-200 个周期。(但free也可能需要更多时间,这应该会显示在分析统计中。)编写一个更好的通用分配器基本上是不可能的,除了技巧和运气。

但是,特定于您的应用程序的模式仍然可以提供机会。我很幸运能够以与创建对象的顺序大致相同的顺序释放对象。

  1. 创建一些内存桶。
  2. malloc以线性方式从桶中返回块。
  3. free将块标记为未使用。这可以利用位图、受管理的智能指针等。对于纯垃圾收集,不需要显式调用。
  4. 当最后一个桶已满时,扫描最后一个最近使用的桶,但只检查是否完全空了。
  5. 如果没有空桶,就做一个新的。

如果有任何碎片,这是一个可怕的策略,但它可以提高malloc几个数量级,因为沿着存储桶扫描直到结束只需要 1-2 个周期而不是 100-200 个周期,并且对于足够少的碎片,你总是可以使扫描频率足够低。

百万分之一的慢速扫描也使这种方法无法应用于许多应用。

我对缓存服务器了解不多,但也许这种方法适用于高度瞬态的 HTTP 连接对象。您需要关注的不是所有malloc,而是以最可预测的模式产生最大成本的分配子集。

于 2013-05-25T01:53:27.473 回答