《Redis设计与实现》读书笔记(十) ——Redis对象相关其他设计与实现

《Redis设计与实现》读书笔记(十) ——Redis对象相关其他设计与实现

(原创内容,转载请注明来源,谢谢)

一、类型检查与命令多态

redis对键操作的命令分为两种,一种是可以对任意键进行操作的命令,如del、expire、rename、type、object等;另一种是只能对特定类型的键进行操作,redis的五种数据类型都有各自特定的键操作命令。

1、类型检查

redis的类型检查,是通过检查redisObject结构的type属性进行的。在执行一个特定命令之前,redis会先检查键对应的值对象的type属性,是否可以执行所需的命令:如果可以执行则执行;否则服务器将拒绝执行,并返回一个类型错误。

2、命令多态

redis每种数据类型,至少都有两种编码方式,命令多态就是指通过一个命令,可以执行不同的编码方式所提供的api。因此,redis的几乎每种操作命令都是多态的。对于同一个类型,操作不同的编码方式,称为基于编码的多态。

另外,还有上述提到的del、expire等,对于任意类型都可以操作,也是多态。这个是基于类型的多态。

二、内存回收

由于实现redis的C语言,不具备垃圾回收功能,因此redis构建了一套内存回收机制,是基于引用计数技术实现的内存回收。通过这一机制,程序可以通过追踪对象的引用计数信息,在适当的时候自动释放对象,并进行内存回收。

引用计数信息是redisObject结构中的refcount属性进行记录。

typedef structredisObject{
int refcount;
}robj;

上面的结构中省略结构中的其他信息。对象引用计数的信息,会随着对象使用状态的变化而改变,如下:

1)创建一个新对象时,refcount值是1。

2)对象被一个新程序使用,refcount值加1。

3)对象不再被某个程序使用,refcount值减1。

4)对象引用计数变成0时,对象所占的内存会被释放。

修改引用计数的api如下:

在对象的整个生命周期,可以分为创建对象、操作对象、释放对象。

三、对象共享

对象的引用计数属性,除了用于内存回收,还可以用于对象的共享。当多个键保存同一个值的时候,且值是整数类型的字符串对象时,redis会使用对象共享,让键指向同一个值。过程如下:

1)将数据库键的值指针指向一个现有的值对象。

2)将被共享的值对象的引用计数增1。

两个对象公用一个值的情况如下图:

对象共享机制对于节约内存有很大的帮助。redis初始化服务器的时候,会创建一万个字符串对象,是从0~9999的整数值,当服务器要用到这些值的时候,会使用共享对象。

共享对象的默认数量,可以通过修改文件redis.h中的常量REDIS_SHARED_INTEGERS进行修改。

因此,当如果创建了两个对象,值都是100,实际上就有三个对象引用,包括两个客户端创建的,和一个服务端持有的,如下图:

除了单独的字符串对象类型,在其他对象类型中,嵌套的字符串对象,也是会共享的。

另外,redis只共享整数类型的字符串对象,不共享字符串类型的字符串对象,是因为共享的对象如果是字符串,则比较字符串是否相同的过程比较耗时;同理,不把字符串对象以外的其他四种对象共享,也是为了避免对比带来的耗时。

四、对象空转时长

redisObject的最后一个属性——lru属性,是用于记录对象的最后一次被访问的时间。

typedef structredisObject{
unsigned lru:22;
}robj;

object idletime命令,可以打印出给定键的空转时长,这一时长是通过当前时间减去lru属性的值确定的。同时,该命令也具有特殊性。其他命令操作键,都会修改键的lru,而object idletime命令仅仅通过查询键的lru计算空转时长,并不修改lru。

如果配置中开启了maxmemory,并且服务器的回收算法设置为volatile-lru或者allkeys-lru,当服务器的内存超过了maxmemory所设定的上限,空转时长较高的键会被优先释放,从而回收内存。

五、redis对象总结

1、redis数据库的每个键和值都是一个redisObject对象。

2、redis有字符串、哈希、列表、集合、有序集合五种对象类型,每种对象类型至少2中编码方式(其中字符串对象有3中编码方式),不同的编码方式在不同的场景中具有高效的特定。

3、服务器执行某些命令之前,会先进行类型检查,对键进行类型检查,是检查键对应的值的类型。

4、redis具有对象的引用回收机制,当对象没有被使用,内存将被回收。

5、redis会共享0~9999共1万个整数值的字符串对象,这个数目可以通过配置文件修改。

6、redis会记录对象的最后访问时间,可以用来计算对象的空转时间。

——written by linhxx 2017.09.02

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-09-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏生信宝典

Linux学习 - SED操作,awk的姊妹篇

awk和sed想一对兄妹,一个出现,就会问起另一个。现在,都来了。 sed基本参数解释 sed是stream editor的简称,擅长对文件进行各种正则操作、插...

1736
来自专栏编程

linux基础(三)

一、文本处理工具 1、文本查看工具less和cat cat -E filename 能看到行的结束符 -A filename 能看到tab键 回车 (hexdu...

1887
来自专栏祥子的故事

Python编程快速上手 让繁琐工作自动化 | 第三章 :实践项目

2656
来自专栏我的博客

调试小技巧file_put_contents() 和var_export以及var_dump

file_put_contents() 函数把一个字符串写入文件中。 我们要将数组打印到文件中,我们可以使用 <?php $arr = array( ‘...

2924
来自专栏逆向技术

C语言第十一讲,预处理命令.

预处理主要是处理以#开头的命令,例如#include <stdio.h>等。预处理命令要放在所有函数之外,而且一般都放在源文件的前面。

430
来自专栏三木的博客

Linux shell 程序设计5——shell中一些特殊符号的用法总结

1、{} 大括号: eg: ls my_{finger,toe}s 这条命令相当于如下两个命令的组合: ls my_fingers ; ls my_toes e...

1636
来自专栏企鹅号快讯

看完这篇文章我知道至少85%的人是没有入门Python的!花两周整理

以前刚学编程的时候就对Python略有耳闻,不过学校只有C,C++,Java,C#。和PHP有句"PHP是最好的语言" 这种家喻户晓的骚话一样,Python也有...

2137
来自专栏kalifaの日々

C语言中static,const和static const 的区别

在第一次调用test()时,如果static int b没有被我赋初值,也会被默认赋值成0。然后执行自增运算,所以输出1。第二次调用test()时如果是普通的变...

371
来自专栏我的博客

php命名空间详解

1、命名空间概述 从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,...

2808
来自专栏C/C++基础

Linux命令(6)——sort命令

以行为单位对文本文件的内容进行排序,将结果显示在标准输出,比较原则是从行首字符向后,依次按ASCII码值进行比较,最后按升序输出。如果file参数指定多个文件,...

372

扫描关注云+社区