为什么dlmalloc分配的块标头包含先前分配的块的4个字节
why dlmalloc allocated chunk header contains 4 bytes of previous allocated chunk
我正在研究一个名为doug-lea内存分配器的动态内存分配器,它使用最佳匹配方法在堆上分配内存。该算法是更多其他算法的基础,但我发现,在分配块的情况下,该块的头部包含前一块的最后4个字节的数据。我查看了算法的解释,但找不到原因。我想知道之前区块的4个字节的分配目的是什么?我还将其解释为在其他块中分配.dtors部分以进行同步和正确使用空间,但我想知道细节。
这是dlmalloc算法的块图
上图包含已分配区块和空闲区块的结构。在空闲区块中,前4个字节包含前一个区块的大小,但在已分配区块中,前四个字节包含前一个已分配区块的最后四个字节用户数据,这对我来说似乎有点困惑,我想知道在当前区块中仅分配前一个分配区块的四个字节的目的是什么。
Yes块确实重叠。从前,记忆是非常昂贵的。这是dlmalloc、ptmalloc和glibcmalloc中的一个特性。
代码中有一个相当不错的解释:
This struct declaration is misleading (but accurate and necessary).
It declares a "view" into memory allowing access to necessary
fields at known offsets from a given base. See explanation below.
struct malloc_chunk {
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
};
malloc_chunk详细信息:
(The following includes lightly edited explanations by Colin Plumb.)
Chunks of memory are maintained using a `boundary tag' method as
described in e.g., Knuth or Standish. (See the paper by Paul
Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
survey of such techniques.) Sizes of free chunks are stored both
in the front of each chunk and at the end. This makes
consolidating fragmented chunks into bigger chunks very fast. The
size fields also hold bits representing whether chunks are free or
in use.
An allocated chunk looks like this:
chunk->+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of previous chunk, if allocated | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of chunk, in bytes |P|
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| User data starts here... .
. .
. (malloc_usable_space() bytes) .
. |
next ->+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Where "chunk" is the front of the chunk for the purpose of most of
the malloc code, but "mem" is the pointer that is returned to the
user. "Nextchunk" is the beginning of the next contiguous chunk.
Chunks always begin on even word boundries, so the mem portion
(which is returned to the user) is also on an even word boundary, and
thus at least double-word aligned.
Free chunks are stored in circular doubly-linked lists, and look like this:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of previous chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`head:' | Size of chunk, in bytes |P|
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Forward pointer to next chunk in list |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Back pointer to previous chunk in list |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Unused space (may be 0 bytes long) .
. .
. |
next-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`foot:' | Size of chunk, in bytes |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The P (PREV_INUSE) bit, stored in the unused low-order bit of the
chunk size (which is always a multiple of two words), is an in-use
bit for the *previous* chunk. If that bit is *clear*, then the
word before the current chunk size contains the previous chunk
size, and can be used to find the front of the previous chunk.
The very first chunk allocated always has this bit set,
preventing access to non-existent (or non-owned) memory. If
prev_inuse is set for any given chunk, then you CANNOT determine
the size of the previous chunk, and might even get a memory
addressing fault when trying to do so.
Note that the `foot' of the current chunk is actually represented
as the prev_size of the NEXT chunk. This makes it easier to
deal with alignments etc but can be very confusing when trying
to extend or adapt this code.
The two exceptions to all this are
1. The special chunk `top' doesn't bother using the
trailing size field since there is no next contiguous chunk
that would have to index off it. After initialization, `top'
is forced to always exist. If it would become less than
MINSIZE bytes long, it is replenished.
2. Chunks allocated via mmap, which have the second-lowest-order
bit (IS_MMAPPED) set in their size fields. Because they are
allocated one-by-one, each must contain its own trailing size field.
我没有专门研究dlmalloc
,但这里有一个可能的解释:
在具有需要16字节对齐的对象的体系结构上(与Intel SSE一样),返回的地址必须是16的倍数。如果报头具有12个字节的信息(包含块的大小)和一些链接信息以将块与前一个块合并,则报头可以被定义为具有16的长度,前四个字节用于前一个分配的块的末尾。如果前一个区块是空闲的,那么分配器可以使用这个空间进行优化。
相关文章:
- C++,在对象内分配多个数据时,堆栈分配是否更有效? 在下面的程序中,类A_Heap的效率会更低吗?
- 使用领带从元组中分配 2 个 lambda
- 为什么 new 第一次分配 1040 个额外的字节?
- 字符串和输入文件,从包含字符串的 txt 文件中分配多个变量值
- 分配两个二元数组
- 计算机如何分配两个变量,我们如何计算两个变量之间的距离?
- 是否可以分配两个不同类型的结构
- 分配两个双精度值,保证产生相同的位集模式
- 在内存中分配多个结构
- 如何根据输入在数组中分配多个索引
- 仅分配第一个字符,将 LPCTSTR 转换为字符*
- 如何在一个呼叫中分配多个变量
- 分配两个 QObject
- 分配两个调用cudaMalloc一次的数组
- 如果我使用共享内存,可以分配多少个块
- 在结构中动态分配多个结构
- 如何分配两个二维数组
- C++强制 new[] 不分配 4 个额外的字节
- 在派生类中同时分配多个字段-为什么这样做有效
- 使用一个"新"分配四个对象数组