动态内存分配器维护着一个进程的虚拟内存区域,称为堆,它紧跟在未初始化的数据区域之后开始向上生长。对于每个进程,内核都维护一个指向堆顶的变量brk。分配器将堆维护为不同大小的块的集合。每个块都是一个连续的虚拟内存片,可以是已分配的也可以是空闲的。C/C++使用显式分配器,并要求用户显式释放分配的块。malloc函数由C标准库提供,用于从堆中分配块。malloc返回一个指向内存块的指针,该内存块的大小至少满足最严格的内存对齐(32位系统上为8字节对齐,64位系统上为16字节对齐)。关于碎片堆利用率低的主要原因是一种称为碎片的现象,碎片有两种形式:内部碎片和外部碎片。内部碎片的产生:分配块大于有效载荷核心。外部碎片的产生:当前的空闲内存加起来足以满足一个分配请求,但是没有一个空闲块大到足以处理这个请求。以上基本内容摘自《深入理解计算机系统》每个Unix进程都有一组特殊的线性区域,这个线性区域就是所谓的堆。线性区的概念参见:《深入理解linux内核》ProcessAddressSpace内存描述符的两个字段分别定义了这个区域的起始地址和结束地址。brk系统调用和mmap系统调用是系统级扩展程序线性区域中的两个系统调用。brk通过调整内存描述符中的堆端地址字段,向内核申请swap区的物理内存或磁盘空间,创建一个新的扩展线性区与申请物理内存或swap磁盘空间的映射关系。mmap类似于brk,但更灵活。它不仅可以映射到物理内存和交换区的磁盘空间,还可以映射到磁盘上的文件。malloc函数基于这两个基本系统调用。由此我们可以想象,malloc主要负责维护空闲堆内存。如有必要,通过brk或mmap扩展线性区域以获得新的内存空间。调用free时,将对应的内存放入空闲内存集合中,等待下一次malloc,如果有满足要求的空闲内存,则分配,否则先合并空闲内存,如果有合并后还是不能满足要求,那就必须通过brk或者mmap申请新的堆内存。最简单的方式,我们用一个链表把所有空闲内存串起来(我们称它为一个chunk,每个chunk代表一个线性区域中的一个地址),但是这样做的效率太低了。Glibc使用以下结构进行内存管理:将一组块串在一起的链表称为bin。malloc中有四种bin:1.fastbin2.unsortedbin3.smallbin4.largebinfastbin的存在是为了small内存的快速分配和释放。unsortedbin是复用最近释放的chunk机制,smallbin和largebin按照存储chunk大小的顺序排列。具体分配策略见:https://blog.csdn.net/T146lLa...https://blog.csdn.net/dongyu_...本人非核心玩家,以上内容摘自其他的博客,只是用来记录和复习,所以打字也不费力气。
