Memcached内存存储
早就听说过Memcached独特的内存管理方式,写着篇文章的目的就是了解Memcached的内存管理,学习其源代码.
1.什么是Slab Allocator
memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存,Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,以期望完全解决内存碎片问题。而且,slab allocator还有重复使用已分配的内存的目的。 也就是说,分配到的内存不会释放,而是重复利用。

2.Slab Allocation的主要术语
Page 分配给Slab的内存空间,默认是1MB,分配给Slab之后根据slab的大小切分成chunk
Chunk 用于缓存记录的内存空间
Slab Class 特定大小的chunk的组

3.Slab初始化
在Memcached启动时候会调用slab的初始化代码(详见memcached.c中main函数调用slabs_init函数).
slabs_init函数声明:
1 |
|
其中limit表示memcached最大使用内存;factor表示slab中chunk size的增长因子,slab中chunk size的大小等于前一个slab的chunk size乘以factor;
memcached.c中main函数调用slabs_init函数:
1 |
|
其中settings.maxbytes默认值为64M,启动memcached使用选项-m设置;settings.factor默认为1.25,启动memcached时候使用-f设置;preallocate指的是启动memcached的时候默认为每种类型slab预先分配一个page的内存,默认是false;
1 |
|
slabs_init函数实现:
1 |
|
其中settings.chunk_size默认为48:
settings.chunk_size = 48; /* space for a modest key and value */
POWER_LARGEST指slab种类的最大值,默认只为200,在memcached.c中设置
#define POWER_LARGEST 200
settings.item_size_max就是每个page的大小,默认1M,在memcached.c中初始化:
settings.item_size_max = 1024 * 1024; /* The famous 1MB upper limit. */
默认不开启预分配,因为很多时候Memcached只存储一种类型的数据(即其大小相对比较固定),这时候其他类型的预分配的slab空间就会浪费.
预分配的逻辑就是从最小的slab开始,为每类slab分配一个Page大小的空间(空间不足时停止分配):
1 |
|
do_slabs_newslab的工作就是为某一个slab分配空间,并将空间划分乘固定大小的chunk:
1 |
|
split_slab_page_into_freelist的主要控制就是Page划分乘chunk并清空:
1 |
|
memcached的内存分配策略就是:按slab需求分配page,各slab按需使用chunk存储.
按需分配的意思就是某一类slab没有对象可存,就不会分配(非preallocate模式),某类slab存储对象很多,就会分配多个slab形成链表.
这里有几个特点要注意:
1.Memcached分配出去的page不会被回收或者重新分配;
2.Memcached申请的内存不会被释放;
3.slab空闲的chunk不会借给任何其他slab使用(新版本memcached有slab_reassign,slab_automove的功能);
slab内存结构图,二维数组链表:

4.往Slab中缓存记录
memcached根据收到的数据的大小,选择最适合数据大小的slab. memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk, 然后将数据缓存于其中.

代码如下:
1 |
|
参数是待存储对象的大小,根据这个大小,从最小的Chunk Size开始查找,找到第一个(即最小的)能放下size大小的对象的Chunk.找不到(size大于最大的Chunk Size)返回0(这就是为什么slab class从1开始而不是从0开始).
如果某个Slab没有剩余的Chunk了,系统便会给这个Slab分配一个新的Page以供使用,如果没有Page可用,系统就会触发LRU机制,通过删除冷数据来为新数据腾出空间,这里有一点需要注意的是:LRU不是全局的,而是针对Slab而言的.
slab内存分配示例:

5.Slab Allocator的缺点
由于Slab Allocator分配的是特定长度的内存,因此无法有效利用分配的内存。 例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。

6.Memcached减少内存浪费
4.1:调整growth factor
(1).估算我们item的大小
key键长+suffix+value值长+结构大小(48字节)
(2).逐步调整growth factor,使得某个slab的大小和我们的item大小接近(必须大于我们item的大小)
7.过期数据
(1).LRU过期策略;
(2).在slab级别上执行LRU策略;
(3).查看是否过去是在get的时候,即懒惰(lazy)检查;
8.memcached-tool脚本
memcached-tool脚本可以方便地获得slab的使用情况 (它将memcached的返回值整理成容易阅读的格式),可以从下面的地址获得脚本: http://www.netingcn.com/demo/memcached-tool.zip
使用方法也极其简单:
1 |
|
比如:
1 |
|
输出示例:
1 |
|
各列的含义为:
# slab class编号
Item_Size Chunk大小
Max_age LRU内最旧的记录的生存时间
1MB_pages 分配给Slab的页数
Count Slab内的记录数
Full? Slab内是否含有空闲chunk
Memcached内存存储的更多相关文章
- memcached全面剖析–2. 理解memcached的内存存储
Slab Allocation机制:整理内存以便重复使用 最近的memcached默认情况下采用了名为Slab Allocator的机制分配.管理内存. 在该机制出现以前,内存的分配是通过对所有记录简 ...
- memcached全面剖析--2.理解memcached的内存存储
下面是<memcached全面剖析>的第二部分. 发表日:2008/7/9 作者:前坂徹(Toru Maesaka) 原文链接:http://gihyo.jp/dev/feature/01 ...
- memcached 内存初始化与key-value存储
本次笔记未涉及到slab的动态重新平衡分配 /**首先介绍一下一个跟内存相关的非常重要的概念,内存块类型数据结构:*/ typedef struct { unsigned int size; /* c ...
- Memcached内存分配优化及使用问题
前几天做了个Memcached的思考,并测试了一些数据,是关于如何提高Memcached内存使用率的问题.在启动memcached的时候可以加-f参数和-n参数.-f指定各slab里面chunk大小的 ...
- memcached内存管理机制[未整理]
memcached默认采用的是Slab Allocator的机制分配管理内存的,在此之前,内存的分配是通过对所有的记录简单地进行malloc和free来进行的,但这种方式容易造成很多内存碎片,加重操作 ...
- memcached内存分配机制
memcached的内存分配没有用到c语言中自带的malloc函数,因为这个函数分配内存的时候效率很低,对于这种要求快速响应,对效率要求非常高的缓存软件来说非常不合适. memcached用的是自己的 ...
- Memcached内存缓存技术
Memcached是什么,有什么作用? Memcached是一个开源的.高性能的内存缓存软件,从名称上看Mem就是内存的意思,而Cache就是缓存的意思. Memcached通过在事先规划好的内存空间 ...
- 03 Memcached内存分布机制
一:Memcached 内存分布机制 (1)把内存分配成slab 和不同大小的chunk.在跟据键值的大小在选择对应的chunk.这样可以减少最小的内存浪费,内存浪费是不可避免的.[把内存划分成若干个 ...
- Redis内存存储结构分析
1 Redis 内存存储结构 本文是基于 Redis-v2.2.4 版本进行分析. 1.1 Redis 内存存储总体结构 Redis 是支持多key-value数据库(表)的,并用 RedisDb 来 ...
随机推荐
- EasyMock入门
这是一个JavaProject,有关EasyMock用法详见本文测试用例 首先是用到的实体类User.java package com.jadyer.model; public class User ...
- Laravel5.3 流程粗粒度分析之bootstrap
从laravel入口文件index里面外面不难定位到Illuminate\Foundation\Http\Kernel的handle方法,同样也不难发现handle方法的核心是 $response = ...
- [ios2] 利用钥匙串,在应用里保存用户密码的方法 【转】
想在应用里保存帐号.密码等信息的话,直接存到 plist 里显然是不负责任的,自己折腾加密既麻烦又不能保证不被反编译破解.实际上苹果 iOS 和 Mac OS X 系统自带了一套敏感信息保存方案:&q ...
- Linux学习笔记(一):常用命令(2)
3.帮助命令 A,帮助命令:man B,其他帮助命令 3.1,格式:man [命令名] 查看命令拥有哪个级别的帮助: ...
- Android 动态监听网络 断网重连
需求: 网络连接断开 弹出popupwindow 当前网络连接断开 网络恢复时popupwindow 消失重新请求网络. 需求描述完毕 上一张帅图 思路:广播 发送及时消息 断网flag popup ...
- Python第一天 安装 shell 文件
Python第一天 安装 shell 文件 python里面一切都是对象 object 代码缩进:建议用四个空格来缩进,不要用tab键 安装 Linux自带python,windows需要下载m ...
- Java定时器Timer简述
概述 主要用于Java线程里指定时间或周期运行任务.Timer是线程安全的,但不提供实时性(real-time)保证. 构造函数 Timer() 默认构造函数. Timer(boolean) 指定关联 ...
- 前端MVC学习笔记(三)——AngularJS服务、路由、内置API、jQueryLite
一.服务 AngularJS功能最基本的组件之一是服务(Service).服务为你的应用提供基于任务的功能.服务可以被视为重复使用的执行一个或多个相关任务的代码块. AngularJS服务是单例对象, ...
- 自定义报表开发(HTML/XML)
定义报表执行的包或存储过程: --创建包头 CREATE OR REPLACE PACKAGE XXPLM_AARONTEST001 IS PROCEDURE MAIN(errbuf OUT VARC ...
- android工具类常用方法
1.获取手机唯一识别号 添加AndroidManifest.xml权限 <uses-permission android:name="android.permission.READ_P ...