对于glibc 2.15,我正在查看malloc.c,特别是free()函数,并对unlink()宏感到困惑。根据消息来源,使用的块看起来像这样:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of previous chunk, if allocated
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of chunk, in bytes
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
User data starts here... .
. .
. (malloc_usable_size() bytes) .
.
nextchunk->+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
和free()'d块看起来像这样:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of previous chunk
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`head:' Size of chunk, in bytes
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Forward pointer to next chunk in list
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Back pointer to previous chunk in list
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Unused space (may be 0 bytes long) .
. .
.
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
当一个使用过的chunk是free()时,它接收它作为参数接收的mem指针,并从中减去一个偏移量以得到一个chunk指针。中间有一堆检查但是在块没有被映射的情况下,它通常向前或向后合并它与另一个空闲块。由于chunk是free()'d已经在bin中,它只是在该特定bin中搜索块来合并它,对吗?在前向合并的情况下,调用unlink()
宏并将其应用于块(free)()之后的块。我不明白这一点,因为当下一个块(称为'nextchunk')被取消链接时,会出现以下代码:
#define unlink(P, BK, FD) {
FD = P->fd;
BK = P->bk;
.
.
.
FD->bk = BK;
BK->fd = FD;
.
.
.
}
如果考虑到BK指向chunk是free()'d并且查看它的结构它没有前向或后向指针,那么如何引用BK->fd
。我一定错过了代码中的部分,其中fd和bk字段被添加到chunk中是免费的()但是我不知道在哪里。有人可以帮忙吗?感谢。
答案 0 :(得分:1)
这一行在被释放的块中创建一个前向指针:
BK->fd = FD;
BK 使用作为一大块用户数据,但现在它是一大块免费数据,因此允许malloc
在内存上涂鸦认为合适。
如果它有帮助,你可以把它想象成一个联盟:
union {
struct {
chunk *fd;
chunk *bk;
} freed;
unsigned char user_data[N];
};
在联盟中,您可以写到任何联盟成员中,但您只能从最近写的成员中读取。因此,当调用free
时,数据会写入fd
和bk
- 这没关系,唯一的结果是user_data
现在可能有垃圾。相比之下,当块包含用户数据(不是免费的)时,fd
和bk
指针都是垃圾,因为它们是别名user_data
。
(从技术上讲,你总是可以从user_data
读取,无论它是什么别名,因为它是unsigned char
,但这并不是真的相关。)
更新:这是低级 C代码。您期望malloc
实现中的低级C代码。字段存在或不存在的想法在低级代码中没有意义,因为我们在不同类型之间进行转换,并允许指向别名。
在低级代码中,字段只是内存偏移量。在我的系统上,fd
字段的偏移量可能为0,bk
字段的偏移量可能为8或4,具体取决于我编译的体系结构。所以下面的代码:
BK->fd = FD;
这意味着“将值FD写入存储单元BK + 0”。如果您认为BK->fd
只是记忆中的一个位置,它可能有助于您了解free
的工作原理。 (它实际上并不是只是内存中的一个位置,因为在编译时还有类型信息和别名规则。)
了解低级C:如果您想了解低级C代码,它可以帮助非常理解汇编语言。这没有必要,但它有所帮助。你学习哪种汇编语言并不重要:x86,MIPS,PowerPC,ARM等。你不需要学习很多汇编语言,只需要一点点。您不需要学习x86,即使您从未使用过MIPS,也可以学习MIPS。 (事实上,MIPS可能更容易学习。)
只需学习足够的装配,即可将一小段C代码转换为装配体,这样您就可以了解它在幕后所做的工作。上面的一行C代码可能会转换为一行汇编代码,因为它非常简单。
当你写 C时,尽量不要考虑汇编。当你编写C时,编译器的编写汇编,这意味着你不是写作大会。