1、需要额外的虚拟存储器时,使用一种动态存储器分配器(dynamic memory allocator)。一个动态存储器分配器维护着一个进程的虚拟存储器区域,称为堆(heap)。在大多数的unix系统中,堆是一个请求二进制0的区域;对于每个进程,内核维护着一个变量brk,它指向堆的顶部。
2、分配器将堆视为一组不同大小的块(block)的集合来维护。每个块就是一个连续的虚拟存储器组块(chunk),要么是已分配的,要么是未分配的。
1)显式分配器(explicit allocator):如通过malloc,free或C++中通过new,delete来分配和释放一个块。
2)隐式分配器(implicit allocator):也叫做垃圾收集器(garbage collector)。自动释放未使用的已分配的块的过程叫做垃圾回收(garbage collection)。
3、malloc不初始化它返回的存储器,calloc是一个基于malloc的包装(wrapper)函数,它将分配的存储器初始化为0。想要改变一个以前已分配的块的大小,可以使用realloc函数。
4、分配器必须对齐块,使得它们可以保存任何类型的数据对象。在大多数系统中,以8字节边界对齐。
不修改已分配的块:分配器只能操作或者改变空闲块。一旦被分配,就不允许修改或者移动它。
5、碎片(fragmentation)
有内部碎片(internal)和外部碎片(external)。
外部碎片:在一个已分配块比有效载荷在时发生的。(如对齐要求,分配最小值限制等)
外部碎片:当空闲存储器合计起来足够满足一个分配请求,但是没有一个单独的空闲块足够大可以来处理这个请求时发生的。
6、隐式空间链表
放置分配的块的策略有:首次适配(first fit),下一次适配(next fit),和最佳适配(best fit)。
如果空闲块已经最大程度的合并,而仍然不能生成一个足够大的块,来满足要求的话,分配器就会向内核请求额外的堆存储器,要么是通过调用nmap,要么是通过调用sbrk函数;分配器都会将额外的(增加的)存储器转化成一个大的空闲块,将这个块插入到空闲链表中,然后将被请求的块放置在这个新的空闲块中。
7、书中对分配器的设计举了一个小例子,10.9.12节。
8、一种流行的减少分配时间的方法,称为分离存储(segregated storage),维护多个空闲链表,其中每个链表中的块有大致相等的大小。
关于“简单分离存储”、“分离适配”、“伙伴系统”等概念,10.9.14节进行了叙述。