0

我正在我的程序中编写一个自定义内存分配器,并试图更好地理解什么是已分配内存和未分配内存。有人告诉我,对于一个基本的“幼稚”sbrk()内存分配器,调用sbrk()必须提供与 16 字节(的倍数)对齐的大小。这意味着如果我需要分配例如 5 个字节的内存,则应用 (5 + (16-1)) & ~(16-1)) 操作,在这种情况下四舍五入为 16。如果请求的大小是 17 而不是 5,那么它将四舍五入为 32。

这意味着我们从操作系统返回的字节数超过了用户为对齐而请求的字节数。我的问题是,11 个字节(在第一个示例的情况下)或 15 个字节(在第二个示例的情况下)是否被视为“已分配”?在内存分配器的正确实现中,用户实际上是否可以在请求的大小和 16 字节边界之间使用超过请求的字节?如果没有,如何执行?

4

3 回答 3

2

没有任何内存分配器将返回的内存块对齐到 16 个字节的一般要求。然而,需要将此与特定机器/平台的最严格对齐要求对齐(即返回的内存块必须适合任何数据类型及其特定机器/平台的对齐要求)。

此外,任何重要的内存分配器很可能会以比通常从malloc(). sbrk()/mmap()(或您的操作系统可能提供的任何工具)在性能方面通常是非常昂贵的操作,并且任何内存分配器都旨在尽可能少地调用它。通常,它将以页面大小(或页面大小的倍数)从操作系统分配内存,并malloc()使用(库特定的)内部管理来满足来自那里的请求,该管理跟踪此(通常较小的)分配并释放维护内部的“免费”列表'。显然,这个“免费列表”必须存在于某个地方。

因为 - 如果不深入了解这个“空闲列表”的位置 - 你无法判断你分配的内存块之外的内存是否由于对齐或库的内部管理要求而“未使用”,触摸该内存将始终自找麻烦。

于 2019-08-18T05:31:21.117 回答
2

我的问题是,11 个字节(在第一个示例的情况下)或 15 个字节(在第二个示例的情况下)是否被视为“已分配”?

不,它们不被视为已分配。更具体地说,这些字节不属于用户程序,它们属于内存分配器。

在内存分配器的正确实现中,用户实际上是否可以在请求的大小和 16 字节边界之间使用超过请求的字节?

不可以,用户的程序只被允许使用被请求的内存。

如果没有,如何执行?

它没有被强制执行。这就是 C 与其他语言不同的地方。C 有很多规则,但它并没有强制执行。程序员必须了解规则,并遵守规则。如果程序员不遵守规则,结果就是未定义的行为。另见这篇文章。用 C 规范的话(强调):

可能的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),到终止翻译或执行(发出的诊断消息)。

于 2019-08-18T17:39:22.013 回答
0

我不认为@EOF 是正确的,@dedecos 也不是完全正确的。

一个合适的内存管理器会在页面中为应用程序分配内存,是的,但只在需要时添加另一个页面,但在每个页面中,内存是按块分配的(在您的示例中:16 字节的块)。

最后一个块中的任何剩余部分(请求 5 个字节的示例中的 11 个字节)都不会分配给 future malloc,甚至 a malloc(5),因为没有小于块增量的打包。这些额外的字节只是浪费空间。

在页面级别以下,内存管理器需要一个位图来跟踪分配:每个最小块大小(在您的情况下为 16 个字节)一个位,因此没有分配小于块的任何内容的规定。

于 2019-08-18T05:37:23.133 回答