这个内存分配器如何获得块的地址?
How does this memory allocator get the address of the block?
所以,我正在阅读此网站上的编写内存分配器:http://dmitrysoshnikov.com/compilers/writing-a-memory-allocator/
我对这部分感到困惑,辅助函数在其中检索块的地址:
/**
* Returns the object header.
*/
Block *getHeader(word_t *data) {
return (Block *)((char *)data + sizeof(std::declval<Block>().data) -
sizeof(Block));
}
这是一个区块:
struct Block {
// -------------------------------------
// 1. Object header
/**
* Block size.
*/
size_t size;
/**
* Whether this block is currently used.
*/
bool used;
/**
* Next block in the list.
*/
Block *next;
// -------------------------------------
// 2. User data
/**
* Payload pointer.
*/
word_t data[1];
};
有人可以解释一下这背后的逻辑吗?
干杯。
内存分配器需要维护有关每个已分配块的大小以及可用的未分配内存所在位置的元数据。分配器通常会在分配的区域本身旁边维护该元数据。这就是示例分配器正在做的事情。 struct Block
表示分配的内存块 包括 其关联的元数据。前三个成员 (size
、used
、next
) 是元数据。 data
对应于呈现给分配器用户的 space(另见下文)。
为了响应分配请求,分配器将选择一个可用块,或者合并或拆分块以获得合适的块,将其标记为已使用,并且 return 指向其 data
的指针成员给调用者。稍后,它将想要再次访问与该数据指针一起使用的元数据,这就是 getHeader()
函数实现的目的:
data
应该是指向 struct Block
. 的 data
成员的指针
- 它被强制转换为类型
char *
,以便指针添加以字节为单位而不是word_t
s。
sizeof(std::declval<Block>().data) - sizeof(Block)
,它是 C++,而不是 C,计算 struct Block
的开头从它的 data
成员开始的(负)偏移量,假设不安全地, struct Block
的布局中没有尾部填充。
- 指针加法因此产生一个指向块开头地址的
char *
,并且
- 将其转换为
Block *
会产生所需的指针。
关于 data
成员的一句话:该成员被声明为长度为 1 的数组,期望分配器用户可以安全地越过其边界。这被称为“struct hack”。尽管它恰好在许多实现中都有效,但它不符合任何 C 或 C++ 标准。因此它的行为是未定义的,你不应该把它作为一个模型来复制。
另请注意附带的注释具有误导性:data
不是指针,而是数据本身(第一个 word_t
)。
所以,我正在阅读此网站上的编写内存分配器:http://dmitrysoshnikov.com/compilers/writing-a-memory-allocator/
我对这部分感到困惑,辅助函数在其中检索块的地址:
/**
* Returns the object header.
*/
Block *getHeader(word_t *data) {
return (Block *)((char *)data + sizeof(std::declval<Block>().data) -
sizeof(Block));
}
这是一个区块:
struct Block {
// -------------------------------------
// 1. Object header
/**
* Block size.
*/
size_t size;
/**
* Whether this block is currently used.
*/
bool used;
/**
* Next block in the list.
*/
Block *next;
// -------------------------------------
// 2. User data
/**
* Payload pointer.
*/
word_t data[1];
};
有人可以解释一下这背后的逻辑吗? 干杯。
内存分配器需要维护有关每个已分配块的大小以及可用的未分配内存所在位置的元数据。分配器通常会在分配的区域本身旁边维护该元数据。这就是示例分配器正在做的事情。 struct Block
表示分配的内存块 包括 其关联的元数据。前三个成员 (size
、used
、next
) 是元数据。 data
对应于呈现给分配器用户的 space(另见下文)。
为了响应分配请求,分配器将选择一个可用块,或者合并或拆分块以获得合适的块,将其标记为已使用,并且 return 指向其 data
的指针成员给调用者。稍后,它将想要再次访问与该数据指针一起使用的元数据,这就是 getHeader()
函数实现的目的:
data
应该是指向struct Block
. 的 - 它被强制转换为类型
char *
,以便指针添加以字节为单位而不是word_t
s。 sizeof(std::declval<Block>().data) - sizeof(Block)
,它是 C++,而不是 C,计算struct Block
的开头从它的data
成员开始的(负)偏移量,假设不安全地,struct Block
的布局中没有尾部填充。- 指针加法因此产生一个指向块开头地址的
char *
,并且 - 将其转换为
Block *
会产生所需的指针。
data
成员的指针
关于 data
成员的一句话:该成员被声明为长度为 1 的数组,期望分配器用户可以安全地越过其边界。这被称为“struct hack”。尽管它恰好在许多实现中都有效,但它不符合任何 C 或 C++ 标准。因此它的行为是未定义的,你不应该把它作为一个模型来复制。
另请注意附带的注释具有误导性:data
不是指针,而是数据本身(第一个 word_t
)。