与内存有关的术语"Arena"是什么意思?

163
我正在阅读一本有关编程概念中的内存的书。在后续章节中,作者频繁使用arena这个词,但从未定义过它。我尝试搜索了这个词汇的含义以及它与内存的关系,但没有找到答案。以下是作者使用该术语的几种情况:

"下一个序列化的例子使用了一种称为从特定 arena 分配内存的策略。"

"……当处理内存泄漏或从特定 arena 中分配时,这很有用。"

"……如果我们想要释放内存,那么我们将释放整个 arena 。"

在一章中,作者使用了100多次这个术语。书中唯一的定义是:

从arena分配 - 首先分配一个arena,然后通过程序自身来管理arena内的分配/释放(而不是由进程内存管理器来管理)。用于压缩和序列化复杂数据结构和对象,或者用于在安全性关键型和/或容错系统中管理内存。

鉴于这些上下文,请问有谁能为我定义arena是什么?

1
这本书叫什么名字? - yaobin
2
@yaobin 在C和C++中的内存作为编程概念,由Frantisek Franek撰写。 - Nocturno
5个回答

182

竞技场只是一块大的连续内存,您可以一次性分配它,然后通过分配该内存的部分来手动管理内存。例如:

char * arena = malloc(HUGE_NUMBER);

unsigned int current = 0;

void * my_malloc(size_t n) { current += n; return arena + current - n; }

关键在于您可以完全控制内存分配的方式。唯一不受您控制的是初始分配的单个库调用。

一个流行的用例是每个区域仅用于分配单个固定大小的内存块。在这种情况下,可以编写非常高效的收回算法。另一个用例是为每个“任务”拥有一个区域,完成任务后,您可以一次性释放整个区域,无需担心跟踪单个释放。

每种技术都非常专业化,通常只有在您确切知道为什么常规库分配不够好时才会派上用场。请注意,良好的内存分配器已经能自己实现许多魔法,并且您需要足够的证据证明它不够好,才开始处理内存。


52
这是一个不错的回答,但请考虑删除或修改最后一段。你真的不需要任何证据。每当你知道 如何 使用内存时,你就比“好的”通用分配器知道更多了,如果你使用这些知识,你的自定义分配器将始终胜出。分配器不是魔法。如果您有许多项目在同一明确定义的时间点全部死亡,则Arena很有用。这几乎是你需要知道的全部。这并不是火箭科学。 - Andreas Haferburg
26
标准库中的内存分配器自动具有比自己编写的自定义分配器更大的优势,即您无需编写/测试/调试/维护等。即使您确信可以通过管理自己的分配来提高性能,但在决定此改进是否值得权衡之前,仍需要有充分的证据。 - ruakh
40
@ruakh 我不喜欢这种所谓的“智慧”,到处都有像“C++之神给了我们它,所以我们必须使用它”这样重复了一百万次的类似于腔调般的东西。还有我最喜欢的: “这是魔法。” 不,这不是魔法。它只是一个算法,简单到甚至计算机都可以运行。在我的书中,这距离魔法相当远。我猜测:你低估了内存分配对性能的影响,并高估了内存池的复杂性。性能是否比开发人员时间更重要是一个商业决策,在SO上讨论这个问题有点无意义。 - Andreas Haferburg
9
@AndreasHaferburg:当然,tcmalloc使用一些特定的算法,其背后的思想很容易解释,但是实现仍然是复杂且非常困难的。最重要的是,为了使内存排序正确,它需要平台特定的知识。我使用“magic”来描述那些用户无法以可移植方式编写的东西(例如高效的互斥锁、tcmalloc或Lambda表达式的类型名称),或者只有通过极端英雄主义才能编写(例如std::function);我并不意味着它们无法被理解。 - Kerrek SB
19
我的最后建议并不是说“比默认值更好”原则上很难实现,而是自定义解决方案的维护成本很高(需要有人编写、文档化、正确地完成任务,并且另一个人必须修复错误,所有人都必须审查和重新验证最初的假设随着使用的扩展),因此您需要证据来证明这种成本是合理的。 - Kerrek SB
显示剩余4条评论

17

我会选择这个 作为可能的答案。

•Memory Arena(也称为break space)--动态运行时内存所存储的区域。内存区域包括堆(heap)和未使用的内存。堆是所有用户分配内存的位置。堆从低地址向高地址增长。

我补充 维基百科的同义词:region, zone, arena, area, 或 memory context。

基本上,这是您从操作系统获取并分配的内存,然后可以一次性释放。这样做的优点是,重复小调用 malloc() 可能会很昂贵(每次内存分配都有性能成本: 分配内存到程序逻辑地址空间所需的时间以及将该地址空间分配给物理内存所需的时间),而如果您知道一个大概的数量,就可以获得一大块内存,然后按照需要将其分配给变量。


14

将其视为“堆”(heap)的同义词。通常,您的进程只有一个堆/区域,所有内存分配都从其中进行。

但有时您会遇到需要将一系列分配组合在一起的情况(例如出于性能、避免碎片化等原因)。这种情况下,最好分配一个新的堆/区域,然后对于任何分配,您可以决定从哪个堆中进行分配。

例如,您可能拥有一个粒子系统,其中频繁地分配和释放相同大小的许多对象。为了避免内存碎片化,您可以从仅用于这些粒子的堆中分配每个粒子,而所有其他分配则来自默认堆。


6

来自http://www.bozemanpass.com/info/linux/malloc/Linux_Heap_Contention.html

libc.so.x共享库中包含glibc组件,堆代码位于其中。当前的堆实现使用多个独立的子堆,称为竞技场。每个竞技场都有自己的互斥锁以进行并发保护。因此,如果进程堆中有足够的竞技场,并且有一种机制将线程的堆访问均匀地分布在它们之间,则争用互斥锁的潜力应该是最小的。事实证明,这对于分配非常有效。在malloc()中,会检查当前目标竞技场的互斥锁是否空闲(trylock)。如果是,则现在锁定竞技场并进行分配。如果互斥锁正在忙碌,则将逐个尝试并使用剩余的竞技场,如果互斥锁未忙碌。如果没有竞技场可以无阻塞地锁定,则创建一个新的竞技场。根据定义,该竞技场尚未锁定,因此分配现在可以继续而不会阻塞。最后,线程上次使用的竞技场的ID保留在线程局部存储中,并在下次由该线程调用malloc()时首先使用。因此,所有对malloc()的调用都将无阻塞地进行。

您还可以参考此链接:

http://www.codeproject.com/Articles/44850/Arena-Allocator-DTOR-and-Embedded-Preallocated-Buf


4
当您发布链接时,应提供摘要,以便如果链接文章消失,您的帖子仍然有用。注意不要改变原意。 - stonemetal
5
这似乎是从http://www.bozemanpass.com/info/linux/malloc/Linux_Heap_Contention.html复制粘贴而来。在直接使用他人原话时,请列出出处。 - jscs

1

分享我对这个问题的理解(答案基于glibc malloc)。

arenaheap是两种不同的内存管理数据结构,它们在不同的层次上工作:arena处于更高的层次。

Arena 一个结构体,在一个或多个线程之间共享,包含对一个或多个堆的引用。默认情况下,每个进程至少有一个arena,即由主线程创建的主要arena。对于多线程程序,将会有多个arena(称为线程arena)。但是线程和arena之间没有一对一的映射关系。因为下面有一个上限来限制arena的数量:

For 32 bit systems:
     Number of arena = 2 * number of cores.
For 64 bit systems:
     Number of arena = 8 * number of cores.

线程竞技场可以包含多个堆,但主竞技场没有多个堆。

一个连续的内存区域,被划分为要分配的块。 每个堆都属于一个竞技场

enter image description here


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