gpt4 book ai didi

c - glibc的free()的内部工作原理

转载 作者:行者123 更新时间:2023-12-02 04:00:41 24 4
gpt4 key购买 nike

对于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()的块看起来像这样:
    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-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

当使用的块为free()时,它将接收到的内存指针作为参数,并从中减去偏移量以获得块指针。两者之间有很多检查,但如果未映射该块,则通常将其与另一个空闲块进行前向或后向合并。由于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指向被free()添加的块,并查看其结构,它没有正向或反向指针,因此如何引用 BK->fd。我一定错过了代码中将fd和bk字段添加到free()将被添加到块中的部分,但我不知道在哪里。有人可以帮忙吗?谢谢。

最佳答案

该行在要释放的块中创建一个前向指针:

BK->fd = FD;

BK曾经是一块用户数据,但是现在它是一块空闲数据,因此 malloc被允许在其认为合适的地方对内存进行涂鸦。

如果有帮助,您可以将其视为一个联合体:
union {
struct {
chunk *fd;
chunk *bk;
} freed;
unsigned char user_data[N];
};

在工会中,您可以写任何工会成员,但只能从最近写入的成员中读取。因此,当调用 free时,会将数据写入 fdbk中-没关系,唯一的结果是 user_data现在可能有垃圾。相比之下,当块包含用户数据(不是免费的)时, fdbk指针是垃圾,因为它们是 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时,编译器在编写汇编,这意味着您不是在编写汇编。

关于c - glibc的free()的内部工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10645722/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com