Memcached源码分析——slab的初始化
以下内容仅为本人的笔记。
/**
* Determines the chunk sizes and initializes the slab class descriptors
* accordingly.
*/
/**
* 确定chunk的大小,初始化slabs类的相应的描述符
*/
void slabs_init(const size_t limit, const double factor, const bool prealloc) {
/**
* #define POWER_SMALLEST 1 //POWER_SMALLEST的定义,表示slab中最少包含一个chunk
* 下面这行中的i为chunk计数器,记录当前slab已经分了多少个chunk,初始值为0
*/
int i = POWER_SMALLEST - ;
/**
* 下面的size为chunk的大小,单位为字节。
* size的大小为item所占内存大小与settings.chunk_size之和
* settings.chunk_size的默认值为48,初始化在memcached-1.4.22/memcached.c的static void settings_init(void);中。
* settings的定义在memcached-1.4.22/memcached.h中。
*/
unsigned int size = sizeof(item) + settings.chunk_size; /**
* 限制使用内存的总量为limit MB,默认为64MB,这个默认值是由 settings.maxbytes 决定的。
*/
mem_limit = limit; /**
* 是否预先在内存中分配一个默认大小为64MB的大chunk,默认 prealloc=false
*/
if (prealloc) {
/* Allocate everything in a big chunk with malloc */
mem_base = malloc(mem_limit);
if (mem_base != NULL) {
mem_current = mem_base;
mem_avail = mem_limit;
} else {
fprintf(stderr, "Warning: Failed to allocate requested memory in"
" one large chunk.\nWill allocate in smaller chunks\n");
}
} /**
* 这行很简单,将slabclass对象的sizeof(slabclass)个字节全部初始化为0
*/
memset(slabclass, , sizeof(slabclass)); /**
* 下面到了具体切割slab的地方了。
* #define POWER_LARGEST 200 //这里定义的是slab的种类最多不得超过200种
* settings.item_size_max为item的最大字节数,默认为1MB。
* factor为chunk的增长系数,即增长为之前的factor倍。默认为1.25。
*/
while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {
/**
* 下面的语句实现的功能:保证items的字节数为CHUNK_ALIGN_BYTES的整数倍
* #define CHUNK_ALIGN_BYTES 8 //CHUNK_ALIGN_BYTES的定义
*/
/* Make sure items are always n-byte aligned */
if (size % CHUNK_ALIGN_BYTES)
size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); /**
* 定义当前slab中的chunk的大小。
*/
slabclass[i].size = size;
/**
* 定义当前slab中的chunk的数目。
*/
slabclass[i].perslab = settings.item_size_max / slabclass[i].size;
size *= factor;
if (settings.verbose > ) {
fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",
i, slabclass[i].size, slabclass[i].perslab);
}
} /**
* 记录一共有多少种slabs
*/
power_largest = i;
/**
* 设置slabs中尺寸最大的chunk的值
*/
slabclass[power_largest].size = settings.item_size_max;
/**
* chunk尺寸最大的slab中chunk的数量
*/
slabclass[power_largest].perslab = ;
if (settings.verbose > ) {
fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",
i, slabclass[i].size, slabclass[i].perslab);
} /* for the test suite: faking of how much we've already malloc'd */
{
char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC");
if (t_initial_malloc) {
mem_malloced = (size_t)atol(t_initial_malloc);
} } /**
* 是否预分配
*/
if (prealloc) {
slabs_preallocate(power_largest);
}
} /**
* powers-of-N allocation structures
*代码在memcached-1.4.22/slabs.c
*/
typedef struct {
unsigned int size; /* sizes of items */
unsigned int perslab; /* how many items per slab */ void *slots; /* list of item ptrs */
unsigned int sl_curr; /* total free items in list */ unsigned int slabs; /* how many slabs were allocated for this class */ void **slab_list; /* array of slab pointers */
unsigned int list_size; /* size of prev array */ unsigned int killing; /* index+1 of dying slab, or zero if none */
size_t requested; /* The number of requested bytes */
} slabclass_t;
static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES]; /**
* memcache中,每一条数据记录在一个item中,item的具体结构如下
* Structure for storing items within memcached.
* 以下代码在memcached-1.4.22/memcached.h的343行到368行
*/
typedef struct _stritem {
struct _stritem *next;
struct _stritem *prev;
struct _stritem *h_next; /* hash chain next */
rel_time_t time; /* least recent access */
rel_time_t exptime; /* expire time */
int nbytes; /* size of data */
unsigned short refcount;
uint8_t nsuffix; /* length of flags-and-length string */
uint8_t it_flags; /* ITEM_* above */
uint8_t slabs_clsid;/* which slab class we're in */
uint8_t nkey; /* key length, w/terminating null and padding */
/* this odd type prevents type-punning issues when we do
* the little shuffle to save space when not using CAS. */
union {
uint64_t cas;
char end;
} data[];
/* if it_flags & ITEM_CAS we have 8 bytes CAS */
/* then null-terminated key */
/* then " flags length\r\n" (no terminating null) */
/* then data with terminating \r\n (no terminating null; it's binary!) */
} item;
slabs_init函数所完成的工作仅仅是初始化slabclass数组,预定义好所有可能会使用到的slab的大小,并没有真正去申请内存空间。只有在真正执行写数据操作的时候才会根据具体数据的大小选择合适大小slab,然后申请空间并存储相关的数据。所以,当使用stats slabs命令查看memcached中已使用的slabs时会发现使用的slabs的编号不是连续的就是这个原因。
如下图:
当使用stats slabs命令查看当前已经使用了哪些slabs时,发现显示的编号是1、4和9,这里其实只存了三条数据:
$str = str_repeat('i',100);
$memc->set('JUST_a_TEST',$str,10);
$str = str_repeat('i',500);
$memc->set('JUST_a_TEST',$str,10);
$str = str_repeat('i',5);
$memc->set('JUST_a_TEST',$str,10);
可见memcached确实是在真正执行写操作是才会去slabclass数组中选择合适大小的slab,然后进行存储的。图中显示的编号其实就是相应slab在slabclass数组中的下标。
这个图中还可以看出一个问题:同一个key存储了三次,每次对应的value大小不一样,没有彼此覆盖,而是一块存在在内存中,这也是memcached使用slab进行存储的一个特点。
Memcached源码分析——slab的初始化的更多相关文章
- memcached源码分析-----slab内存分配器
温馨提示:本文用到了一些可以在启动memcached设置的全局变量.关于这些全局变量的含义可以参考<memcached启动参数详解>.对于这些全局变量,处理方式就像<如何阅读memc ...
- Memcached源码分析之内存管理
先再说明一下,我本次分析的memcached版本是1.4.20,有些旧的版本关于内存管理的机制和数据结构与1.4.20有一定的差异(本文中会提到). 一)模型分析在开始解剖memcached关于内存管 ...
- memcached源码分析-----item过期失效处理以及LRU爬虫
memcached源码分析-----item过期失效处理以及LRU爬虫,memcached-----item 转载请注明出处:http://blog.csdn.net/luotuo44/article ...
- Memcached源码分析之请求处理(状态机)
作者:Calix 一)上文 在上一篇线程模型的分析中,我们知道,worker线程和主线程都调用了同一个函数,conn_new进行事件监听,并返回conn结构体对象.最终有事件到达时,调用同一个函数ev ...
- Memcached源码分析之线程模型
作者:Calix 一)模型分析 memcached到底是如何处理我们的网络连接的? memcached通过epoll(使用libevent,下面具体再讲)实现异步的服务器,但仍然使用多线程,主要有两种 ...
- Memcached源码分析之从SET命令开始说起
作者:Calix 如果直接把memcached的源码从main函数开始说,恐怕会有点头大,所以这里以一句经典的“SET”命令简单地开个头,算是回忆一下memcached的作用,后面的结构篇中关于命令解 ...
- Memcached源码分析
作者:Calix,转载请注明出处:http://calixwu.com 最近研究了一下memcached的源码,在这里系统总结了一下笔记和理解,写了几 篇源码分析和大家分享,整个系列分为“结构篇”和“ ...
- Spring IOC 容器源码分析 - 余下的初始化工作
1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...
- SDL2源码分析1:初始化(SDL_Init())
===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...
随机推荐
- mac下的改装人生——第一次拆卸mbp,加入内存
这是我第一次拆我的mbp哈,心情无比激动. 在家门口电脑维修店的老板那里借来了螺丝刀.回家以后立刻开始了改装行动 我的MC700后盖是可以全部打开的,总共大概是10个螺丝的样子,上面靠右边的三颗是长螺 ...
- Windows下移动硬盘无法识别但是Mac下可以识别
今天遇到一个问题,具体如下: 在Mac下正常使用的移动硬盘,在Windows下无法识别,打开显示"磁盘结构损坏且无法读取" 分析:Mac下既然能够正常使用,那么硬盘就应该是正常的, ...
- centos 5 yum安装与配置vsFTPd FTP服务器
vsftpd作为FTP服务器,在Linux系统中是非常常用的.下面我们介绍如何在centos系统上安装vsftp. 什么是vsftpd vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序 ...
- Azkaban2配置过程
Azkaban2配置过程 azkaban2所需环境:jdk1.6.ant.jetty.hadoop.ssl证书 通过http://azkaban.github.io/azkaban2/download ...
- Oracle 数据库 Database Express Edition 11g Release 2 (11.2) 错误解决集锦(使用语法)
ORA-14552: 在查询或 DML 中无法执行 DDL, 提交或回退 PL/SQL“ORA-14551:无法在查询中执行DML操作 解决:在声明函数时加上: PRAGMA AUTONOMOUS_T ...
- loadView,viewDidLoad等几种方法的调用总结
viewDidLoad 此方法只有当view从nib文件初始化的时候才被调用.viewDidLoad用于初始化,加载时用到的. loadView 此方法在控制器的view为nil的时候被调用.虽然经常 ...
- TCP异常终止(reset报文)
在之前做智能家居系统时,师弟做的服务端与WiFI盒子(客户端)进行通信时,总是出现异常情况,然后服务端不停地向客户端发送RESET报文,之前一直都不知道是什么情况,因此一直不知道是什么问题导致的,今天 ...
- php 链式操作的实现 学习记录
php 面向对象中实现链式操作的关键部分:调用的方法中返回当前对象 ,从而实现链式操作: <?php namespace commom; class db { public function w ...
- 【开源java游戏框架libgdx专题】-10-核心库-Viewport
Viewport类,又称为视口类,主要负责管理游戏相机,处理游戏世界坐标与布景层坐标的换算关系.在移动端开发,不像PC端容易.因为要适配不同分辨率的设备.libgdx处理不同的设备屏幕时,用视口处理舞 ...
- C# 邮件发送注意事项
使用QQ邮箱作为smtp服务器时,遇到 "命令顺序不正确. 服务器响应为: AUTH first..",解决办法: smtpClient.UseDefaultCredentials ...