【内存管理】概要

首先,列个计划吧。未来一周的blog分两个方向:一、内存管理,就基本使用,内存池,一些典型的内存管理算法如slab算法,tcmalloc的管理算法等做学习介绍;二、搜索引擎的基本概念、架构的学习;

C语言的内存分配

  • malloc:该函数分配给定的字节数,并返回一个指向它们的指针。如果没有足够的可用内存,那么它返回一个空指针。
  • free:该函数获得指向由 malloc 分配的内存片段的指针,并将其释放,以便以后的程序或操作系统使用(实际上,一些 malloc 实现只能将内存归还给程序,而无法将内存归还给操作系统)。

虚拟内存&物理内存

概念:虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

碎片:由于虚拟内存使用了硬盘,硬盘上非连续写入的文件会产生磁盘碎片,因此一旦用于实现虚拟内存的文件或分区过于零碎,会加长硬盘的寻道时间,影响系统性能。

常用的内存管理

  • memcached的内存管理

        memcached对内存的管理采用slab分配算法,根据powers of 2来将1MB的内存块划分成多个小内存块,其中这1MB的内存块称之为页。Powersof 2是2的n次方的意思,例如:2的0次方是1,2的1次方是2,2的2次方是4,2的3次方是8等等。以此类推,1MB的内存按2的n次方划分可以划分成20种不同的内存块。memcached是通过slabclass_t结构体来管理这些小内存块的,slabclass_t的定义如下面代码所示。

        slots指针指向的是内存分配器回收的小内存块的数组,sl_total保存了回收器的容量,当回收器容量不足时,需要重新分配更大的内存来作为回收器, sl_curr是当前回收器回收到的位置,下一个回收的内存块就会放到这里。end_page_ptr保存的是当前的空闲内存块,end_page_free保存的是当前空闲块的数量,如果end_page_free等于0表示已经没有空闲内存块了,需要向系统申请一块新的内存页。slab_list保存的是申请的内存页, slabs保存的是已经申请的内存页数量。

typedef struct {
    unsigned int size;     
    unsigned int perslab;  
    void **slots;          
    unsigned int sl_total; 
    unsigned int sl_curr;  
    void *end_page_ptr;
    unsigned int end_page_free;
    unsigned int slabs;    
    void **slab_list;      
    unsigned int list_size;
    unsigned int killing; 
} slabclass_t;

另外,Memcached中通过一个增长因子来控制每级内存大小的分配,应用可以配置合适的因子以减少内存的浪费。

Slab算法相对比较简单和稳定,也具有较好的动态特性,但其最主要的问题是没有回收,对于我们多产品线混合运维的cache服务来说,其内存大小跨度大、变化大,这使得小内存被分配后很有可能就没人使用了,这样导致的内存浪费会比较严重。

  • spcache

spcache的内存和磁盘采用静态配置的方式进行管理,可以配置多个定长段,以及每个定长段的个数。这种方式避免了碎片的产生,对于单个产品线来说,能够有一些方法确定配置哪些级别长度更合适,但同样对于多产品线混合运维的cache服务,每个产品线为其单独进行配置使得维护极其复杂,统一配置又会导致空间浪费很严重。

  • tcmalloc

tcmalloc是google实现的一套内存管理机制,它的特点是高效。Tcmalloc执行一次小对象的分配释放大约要50纳秒,glibc的malloc、free大约要300纳秒。Tcmalloc的内存缓存分线程和进程,内存分配时首先在线程缓存中找,找不到再去进程缓存中找,再找不到则让系统分配,释放时同样,先放回线程,线程空闲的较多则放会进程,这种方式对于多线程程序减少了很多内存分配释放的冲突代价。

Tcmalloc区分大对象和小对象,小于等于32K的为小对象,大对象直接使用页分配器(一个页是一个4K的对齐内存区域)从中央堆直接分配。即,一个大对象总是页对齐并占据整数个连续页。每个小对象的大小被映射到170个可分配的尺寸类别中的一个。一个线程缓存对每个尺寸都包括一个自由对象的链表。分配时只要映射到一个尺寸链表上,然后直接取,如果没有,再从该尺寸的中央自由链表(进程级)取若干个。大对象的分配由中央分配堆来处理,中央分配堆维护一个不同连续页个数的自由链表阵列,分配时取连续的页。



引用:

内存管理内幕:http://www.ibm.com/developerworks/cn/linux/l-memory/

百度百科-虚拟内存:http://baike.baidu.com/view/976.htm



你可能感兴趣的:(【内存管理】概要)