填充字节是否在内存分配器中被视为已分配或未分配?
Are padding bytes considered allocated or unallocated in a memory allocator?
我正在我的程序中编写一个自定义内存分配器,并试图更好地理解什么是已分配内存和未分配内存。有人告诉我,对于基本的 "naive" sbrk()
内存分配器,对 sbrk()
的调用必须提供与 16 字节(的倍数)对齐的大小。这意味着如果我需要分配例如 5 个字节的内存,则应用 (5 + (16-1)) & ~(16-1)) 操作,在本例中四舍五入为 16。如果请求的大小是 17 而不是 5,那么它将四舍五入为 32。
这意味着我们从操作系统返回的字节数多于用户为了对齐而请求的字节数。我的问题是,11 个字节(在第一个示例的情况下)或 15 个字节(在第二个示例的情况下)是否被视为 "allocated"?在内存分配器的正确实现中,用户实际上可以在请求的大小和 16 字节边界之间使用多于请求的字节吗?如果不是,这是如何执行的?
没有任何内存分配器将返回的内存块对齐到 16 字节的一般要求。但是,需要将其与特定 machine/platform 的最严格对齐要求对齐(即返回的内存块必须适合任何数据类型及其特定 machine/platform 具有的对齐要求)。
此外,任何重要的内存分配器很可能会从 OS 中请求比通常从 malloc()
中请求的大得多的内存块。 sbrk()/mmap()
(或您的 OS 可能提供的任何设施)在性能方面通常是相当昂贵的操作,任何内存分配器都旨在尽可能少地调用它。通常,它将以页面大小(或其倍数)的块从 OS 分配内存,并使用(特定于库的)内部管理来满足来自那里的 malloc()
请求,该内部管理跟踪此(通常较小) 分配和释放维护内部 'free list'。
显然,这个'free list'一定住在什么地方。
因为 - 不知道这个 'free list' 所在的位置 - 你无法判断你分配的内存块之外的内存是否存在 'unused' 因为对齐或因为库的内部管理要求,触摸内存总是会带来严重的麻烦。
我认为@EOF 不正确,@dedecos 也不完全正确。
一个合适的内存管理器会以页面为单位为应用程序分配内存,是的,但只在需要时添加另一个页面,但在每个页面中,内存是按块分配的(在您的示例中:16 字节的块)。
最后一个块中的任何剩余部分(您请求 5 个字节的示例中的 11 个字节)将 不会 分配给未来的 malloc
,即使是 malloc(5)
,因为没有比块增量更小的打包。那些额外的字节只是被浪费了 space.
在页面级别以下,内存管理器需要位图来跟踪分配:每个最小块大小一位(在您的情况下为 16 字节),因此没有规定分配小于块的任何内容。
My question is, are the 11 bytes (in the case of the first example) or
15 bytes (in the case of the second example) considered "allocated" or
not?
不,它们不被视为已分配。更具体地说,那些字节不属于用户程序,它们属于内存分配器。
In a proper implementation of a memory allocator, could the user
actually use more than the requested bytes between the requested size
and the 16 byte boundary?
不,用户的程序只允许使用请求的内存。
If not, how is this enforced?
没有强制执行。这是 C 语言区别于其他语言的地方。 C有很多规则,但它不强制执行。程序员必须了解规则,并遵守规则。如果程序员不遵守规则,结果就是undefined behavior. See also this post。用C规范的话来说(重点加了):
Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of a
diagnostic message).
我正在我的程序中编写一个自定义内存分配器,并试图更好地理解什么是已分配内存和未分配内存。有人告诉我,对于基本的 "naive" sbrk()
内存分配器,对 sbrk()
的调用必须提供与 16 字节(的倍数)对齐的大小。这意味着如果我需要分配例如 5 个字节的内存,则应用 (5 + (16-1)) & ~(16-1)) 操作,在本例中四舍五入为 16。如果请求的大小是 17 而不是 5,那么它将四舍五入为 32。
这意味着我们从操作系统返回的字节数多于用户为了对齐而请求的字节数。我的问题是,11 个字节(在第一个示例的情况下)或 15 个字节(在第二个示例的情况下)是否被视为 "allocated"?在内存分配器的正确实现中,用户实际上可以在请求的大小和 16 字节边界之间使用多于请求的字节吗?如果不是,这是如何执行的?
没有任何内存分配器将返回的内存块对齐到 16 字节的一般要求。但是,需要将其与特定 machine/platform 的最严格对齐要求对齐(即返回的内存块必须适合任何数据类型及其特定 machine/platform 具有的对齐要求)。
此外,任何重要的内存分配器很可能会从 OS 中请求比通常从 malloc()
中请求的大得多的内存块。 sbrk()/mmap()
(或您的 OS 可能提供的任何设施)在性能方面通常是相当昂贵的操作,任何内存分配器都旨在尽可能少地调用它。通常,它将以页面大小(或其倍数)的块从 OS 分配内存,并使用(特定于库的)内部管理来满足来自那里的 malloc()
请求,该内部管理跟踪此(通常较小) 分配和释放维护内部 'free list'。
显然,这个'free list'一定住在什么地方。
因为 - 不知道这个 'free list' 所在的位置 - 你无法判断你分配的内存块之外的内存是否存在 'unused' 因为对齐或因为库的内部管理要求,触摸内存总是会带来严重的麻烦。
我认为@EOF 不正确,@dedecos 也不完全正确。
一个合适的内存管理器会以页面为单位为应用程序分配内存,是的,但只在需要时添加另一个页面,但在每个页面中,内存是按块分配的(在您的示例中:16 字节的块)。
最后一个块中的任何剩余部分(您请求 5 个字节的示例中的 11 个字节)将 不会 分配给未来的 malloc
,即使是 malloc(5)
,因为没有比块增量更小的打包。那些额外的字节只是被浪费了 space.
在页面级别以下,内存管理器需要位图来跟踪分配:每个最小块大小一位(在您的情况下为 16 字节),因此没有规定分配小于块的任何内容。
My question is, are the 11 bytes (in the case of the first example) or 15 bytes (in the case of the second example) considered "allocated" or not?
不,它们不被视为已分配。更具体地说,那些字节不属于用户程序,它们属于内存分配器。
In a proper implementation of a memory allocator, could the user actually use more than the requested bytes between the requested size and the 16 byte boundary?
不,用户的程序只允许使用请求的内存。
If not, how is this enforced?
没有强制执行。这是 C 语言区别于其他语言的地方。 C有很多规则,但它不强制执行。程序员必须了解规则,并遵守规则。如果程序员不遵守规则,结果就是undefined behavior. See also this post。用C规范的话来说(重点加了):
Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).