memcached源码分析之内存管理 — Slab Allocator (一)
memcached简介:
许多 Web 应用都将数据保存到 RDBMS 中,应用服务器从中读取数据并在浏览器中 显示。但随着数据量的增大、访问的集中,就会出现 RDBMS 的负担加重、数据库 响应恶化、网站显示延迟等重大影响。这时就该 memcached 大显身手了。memcached 是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态 Web 应用的速度、提高可扩展性。大家可以从这里 memcached-1.4.15下载我们分析的memcached版本,或者可以直接从官网下载。
slab allocator简介:
memcached采用了一种名为Slab Allocator的机制分配、管理内存。相比于之前简单的调用malloc / free函数来进行内存分配,Slab Allocator机制的引入大大减少了内存碎片的存在,这样也就大大减少了操作系统内存管理的负担,大大提升了memcached的性能。
Slab Allocator机制的目标:
引用一下摘自memcached文档中的话:
the primary goal of the slabs subsystem in memcached was to eliminate memory fragmentation issues totally by using fixed-size memory chunks coming from a few predetermined size classes.
可见slab allocator就是为了减少内存碎片而生的。它的基本机制为,按照指定的大小,将内存切分为指定长度的内存块并对其实施管理。之后如果memcached需要为某一个存储项申请内存的时候则直接从其管理的内存块中进行申请,而不是直接调用malloc / free函数来向系统提出请求(因为malloc在申请小块内存的时候通常会导致非常严重的内存碎片)。
Slab Allocator在memcached中角色:
每当有用户需要向memcached中插入键值对的时候,memcached都要去获得用于存储这些键值对的内存块。一个简单的方法是直接调用malloc函数获取内存,但是这样做得弊端是会照成系统产生大量的内存碎片,因此如果过度频繁的调用malloc/free其效率是非常低下的。这是为了解决这一问题,slab allocator才被引入到memcached得内存管理中。如图可见,当memcached需要获取内存去存储键值对时,它首先会向items模块作申请(items模块将在下一篇文章中进行介绍),如果items模块不能满足,则items模块再向slab allocator进行申请。因此slab allocator在整个memcached中扮演着一个最底层的内存管理者的角色。
Slab Allocator 的机制:
Slab allocator的机制很简单,但是要了解其机制必须要先对chunk的相关概念有一个了解。
chunk: slabclass中管理的固定大小的内存块,不同slabclass所管理的chunk大小不同。(如果还不清楚的看下图吧)
Slab allocator将内存划分为不同尺寸的内存块(chunk),然后把相同尺寸的chunk划分到一个chunk集中,一个slabclass便包含了这样的一类大小的chunk集。Slab allocator维护了一个slabclass的数组,这样slab allocator便拥有了众多不同大小的chunk集。如,下图:
每当用户向slab allocator申请内存的时候,slab allocator都会在其slabclass数组中寻找最合适的分配者(slabclass)为用户分配一个chunk,chunk的大小可能会比用户需求的稍大。
例如:继续考虑上图的情形,现在系统中维护的slabclass数组大小为3。这三个slabclass分别管理者大小为16,24,36的chunk集合(可见不同的slabclass之间的chunk大小事成比例增长的,此处为1.5)。假设现在有一个用户要申请18个字节大小的内存块,那么slab allocator将会从slabclass[2]中为其分配一个chunk。因为slabclass[1]中chunk的大小为16显然不能满足用户的需求,而slabclass[3]中的chunk的大小为36,相对于slabclass[2]而言,如果从slabclass[3]分配chunk照成的浪费将比从slabclass[2]中进行分配大得多,因此从slabclass[2]中进行分配是最合适的。