3

我打算编写一个 C++ 网络应用程序,其中:

  1. 我使用单个线程来接受 TCP 连接并从中读取数据。我打算使用 epoll/select 来做到这一点。数据被写入使用一些竞技场分配器分配的缓冲区,比如jemalloc。
  2. 一旦来自单个 TCP 客户端的数据足以形成协议消息,数据就会发布在环形缓冲区上。环形缓冲区结构包含连接的 fd 和指向包含相关数据的缓冲区的指针。
  3. 工作线程处理来自环形缓冲区的条目并将一些结果数据发送到客户端。处理完每个事件后,工作线程释放实际的数据缓冲区,将其返回到 arena 分配器以供重新使用。

我将省略有关发布者如何使其写入的数据对工作线程可见的详细信息。

所以我的问题是:是否有任何分配器针对这种行为进行优化,即在一个线程上分配对象并在另一个线程上释放?

我特别担心必须使用锁将内存返回到不是线程关联竞技场的竞技场。我也担心虚假共享,因为生产者线程和工作线程都会写入同一个区域。似乎 jemalloc 或 tcmalloc 都没有为此进行优化。

4

2 回答 2

3

处理内存分配和释放问题的最佳方法是不处理它。

你提到了一个环形缓冲区。这些通常是固定大小。如果你能为你的协议消息提供一个固定的最大大小,你就可以分配你在程序启动时需要的所有内存。释放时,保留内存但将其重置为新状态。

现在,您的程序可能需要在处理每条消息时分配和取消分配内存,但这将在每个线程中完成,并且不会出现跨线程问题。

即使您的消息最大大小太大而无法预先分配,如果您可以分配大多数消息将使用的内存量并且在必要时具有分配更多的处理程序,这也可以工作。

于 2013-10-02T23:13:45.927 回答
3

在为您的多线程应用程序实现高度优化的分配器之前,您应该首先将标准newdelete运算符用于您的实现。正确实现应用程序后,您可以着手解决通过分析发现的瓶颈问题。

new如果您到了标准和分配器显然是delete应用程序瓶颈的阶段,以下是我使用的方法:

假设:线程数是固定的并且是静态创建的。

  • 每个线程都有自己的竞技场。
  • 从 arena 中取出的每个对象都有一个指向它来自的 arena 的引用。
  • 每个 arena 对每个线程都有一个单独的垃圾列表。
  • 当一个线程释放一个对象时,它会返回它来自的arena,但会被放置在线程特定的垃圾列表中。
  • 实际拥有竞技场的线程将其垃圾列表视为真正的空闲列表。
  • 定期地,拥有一个 arena 的线程执行一次垃圾收集传递,以将其他线程垃圾列表中的对象折叠到真正的空闲列表中。

“定期”垃圾收集过程不一定要基于时间。例如,可以在每次分配时回收并释放一部分垃圾。

于 2013-10-02T23:05:36.873 回答