提问人:bodacydo 提问时间:8/14/2010 最后编辑:orlpbodacydo 更新时间:9/21/2020 访问量:166539
malloc() 是如何在内部实现的?[复制]
How is malloc() implemented internally? [duplicate]
问:
谁能解释一下内部是如何工作的?malloc()
我有时这样做,我看到很多系统调用,谈论它被用于,但仅此而已。strace program
sbrk
man sbrk
malloc()
答:
系统调用移动数据段的“边界”。这意味着它移动了程序可以读取/写入数据的区域的边界(让它增长或缩小,尽管AFAIK没有真正使用该方法将内存段返回内核)。除此之外,还有用于将文件映射到内存,但也用于分配内存(如果您需要分配共享内存,那就是您的方式)。sbrk
malloc
mmap
mmap
因此,您有两种方法可以从内核获取更多内存:和 .关于如何组织从内核获得的内存,有多种策略。sbrk
mmap
一种幼稚的方法是将其划分为多个区域,通常称为“桶”,这些区域专用于某些结构大小。例如,实现可以为 16、64、256 和 1024 字节结构创建存储桶。如果您要求为您提供给定大小的内存,它会将该数字四舍五入到下一个存储桶大小,然后从该存储桶中为您提供一个元素。如果需要,可以使用更大的区域直接与内核进行分配。如果一定大小的存储桶是空的,则可以为新存储桶获得更多空间。malloc
malloc
malloc
mmap
malloc
sbrk
有各种各样的设计,可能没有一种真正的实现方式,因为您需要在速度、开销和避免碎片化/空间效率之间做出妥协。例如,如果存储桶的元素用完了,则实现可能会从更大的存储桶中获取元素,将其拆分并将其添加到元素用完的存储桶中。这将非常节省空间,但并非每个设计都可行。如果您只是通过 / 获得另一个桶,那可能会更快、更容易,但不会节省空间。此外,设计当然必须考虑到“免费”需要以某种方式再次提供空间。您不会只分发内存而不重复使用内存。malloc
malloc
sbrk
mmap
malloc
如果您有兴趣,OpenSER/Kamailio SIP 代理有两种实现(它们需要自己的实现,因为它们大量使用共享内存,并且系统不支持共享内存)。请参见:https://github.com/OpenSIPS/opensips/tree/master/memmalloc
malloc
然后你也可以看看 GNU libc malloc
实现,但那个非常复杂,IIRC。
评论
简单地说,像这样工作:malloc
free
malloc
提供对进程堆的访问。堆是 C 核心库(通常是 libc)中的一种构造,它允许对象获得对进程堆上某些空间的独占访问权限。
堆上的每个分配都称为堆单元。这通常由一个标头组成,该标头包含有关单元大小的信息,以及指向下一个堆单元的指针。这使得堆实际上成为链表。
当启动一个进程时,堆包含一个单元,其中包含启动时分配的所有堆空间。此单元格存在于堆的可用列表中。
当调用 时,将从大型堆单元中获取内存,该堆单元由 返回。其余部分形成一个新的堆单元,该堆单元由内存的所有其他部分组成。malloc
malloc
当释放内存时,堆单元将添加到堆的可用列表的末尾。随后在自由列表中寻找合适大小的单元格。malloc
可以预料,堆可能会碎片化,堆管理器可能会不时尝试合并相邻的堆单元。
当可用列表中没有剩余内存用于所需分配时,调用或系统调用从操作系统请求更多内存页。malloc
brk
sbrk
现在,有一些修改可以优化堆操作。
- 对于大型内存分配 (通常> 512 字节,堆 管理器可以直接进入操作系统,然后 分配一个完整的内存页。
- 堆 可以指定最小大小 分配以防止大量资金 的碎片化。
- 堆还可以将自身划分为多个箱,一个用于小分配,一个用于较大的分配,以更快地进行较大的分配。
- 还有一些巧妙的机制可以优化多线程堆分配。
同样重要的是要认识到,简单地移动程序中断指针,实际上并没有分配内存,它只是设置了地址空间。例如,在 Linux 上,当访问该地址范围时,内存将由实际的物理页“备份”,这将导致页面错误,并最终导致内核调用页面分配器以获取备份页。brk
sbrk
评论