redis系列之------对象
前言
Redis 并没有直接使用数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统, 这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象, 每种对象都用到了至少一种我们前面所介绍的数据结构。
通过这五种不同类型的对象, Redis 可以在执行命令之前, 根据对象的类型来判断一个对象是否可以执行给定的命令。 使用对象的另一个好处是, 我们可以针对不同的使用场景, 为对象设置多种不同的数据结构实现, 从而优化对象在不同场景下的使用效率。
除此之外, Redis 的对象系统还实现了基于引用计数技术的内存回收机制: 当程序不再使用某个对象的时候, 这个对象所占用的内存就会被自动释放; 另外, Redis 还通过引用计数技术实现了对象共享机制, 这一机制可以在适当的条件下, 通过让多个数据库键共享同一个对象来节约内存。
对象的类型与编码
Redis 使用对象来表示数据库中的键和值, 每次当我们在 Redis 的数据库中新创建一个键值对时, 我们至少会创建两个对象, 一个对象用作键值对的键(键对象), 另一个对象用作键值对的值(值对象)。
Redis 中的每个对象都由一个 redisObject 结构表示, 该结构中和保存数据有关的三个属性分别是 type 属性、 encoding 属性和 ptr 属性:
typedef struct redisObject {
// 类型
unsigned type:;
// 编码
unsigned encoding:;
// 指向底层实现数据结构的指针
void *ptr;
// ...
} robj;
我们可以看到一个对象中主要包含了三种字段。
type: 表示对象的类型。比如String,List,Hash等等
encoding:表示对象底层用的是什么数据结构。如INT(整数),EMBSTR(简洁版sds),RAW(sds),HT(map)等等
ptr:ptr是一个指针,指向对象所用的数据结构。
如下图所示:
set k v
k是String类型,embstr数据结构,也就是简洁版的sds,后续讲。

embstr与sds区别
之前我们讲数据结构,都没有见到过embStr,是的,我也是看到这一节才知道有这个东西的。
Redis为了优化,搞了一个embStr,他是为了专门存短字符串的一种编码优化方式。
embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次。raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构, 而embstr编码则通过调用一次内存分配函数来分配一块连续的空间, 空间中依次包含redisObject和sdshdr两个结构。因为一个连续,一个不连续。
- 释放
embstr编码的字符串对象只需要调用一次内存释放函数, 而释放raw编码的字符串对象需要调用两次内存释放函数。理由同上
- 因为
embstr编码的字符串对象的所有数据都保存在一块连续的内存里面, 所以这种编码的字符串对象比起raw编码的字符串对象能够更好地利用缓存带来的优势。
总的来说,因为embstr分配的是一段连续的内存,使得它分配释放内存都是一次,所以效率会有所提高。同时embste <==> sds 为44个字节。
从下图中,我们可以明确看到。 len <= 44 都是embster的数据结构,如果len > 44 则转变为raw。至于为啥44。
大家可以去算一下。参考文章:
https://zhuanlan.zhihu.com/p/67876900
https://xiaoyue26.github.io/2019/01/19/2019-01/redis%E7%9A%84embstr%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF39B/

内存
Redis为了节省内存,真的是操碎了心。
c语言不像Java,Go等语言,本身不具备自动回收内存机制。Java的内存回收导致STW一直被人诟病,最近看了ZGC的数据,Java真的是崛起了。
因此Redis 在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制, 通过这一机制, 程序可以通过跟踪对象的引用计数信息, 在适当的时候自动释放对象并进行内存回收。
但熟悉JVM的都知道,引用计数他有一种缺陷就是,解决不了循环引用的问题。
如 A <==> B 但已经没有其他任何节点引用AB了,但AB由于相互引用,计数为1,永远不会被回收。所以Java用了GC ROOT。
但Redis不知道为啥不存在这个问题,找了资料,也没找出什么原因。大多都说Redis没有复杂的结构,所以?有大佬能解答下不?
引用计数我们可以通过 OBJECT refcount token 命令,查询到token被引用了几次,如果为0,那么则可以回收了。
还有最重要的一点是,Redis对整数 0-9999(共1W个整数)做了缓存。类似于Java对-128-127做缓存一样。
但是没有对值的字符串,如aaaaa的这种缓存,毕竟判断一个字符串是否在库里面,需要扫整个库,非常耗时,并且cpu压力非常的大。
处于优化,折中的考虑,也就缓存了0-9999吧。其实看看淘宝商品的价格,缓存0-100足矣,毕竟0-100占据了99%的商品。
具体可看:http://redisbook.com/preview/object/share_object.html
后言
- Redis 数据库中的每个键值对的键和值都是一个对象。
- Redis 共有字符串、列表、哈希、集合、有序集合五种类型的对象, 每种类型的对象至少都有两种或以上的编码方式, 不同的编码可以在不同的使用场景上优化对象的使用效率。
- 服务器在执行某些命令之前, 会先检查给定键的类型能否执行指定的命令, 而检查一个键的类型就是检查键的值对象的类型。
- Redis 的对象系统带有引用计数实现的内存回收机制, 当一个对象不再被使用时, 该对象所占用的内存就会被自动释放。
- Redis 会共享值为 0 到 9999 的整数对象。
- 对象会记录自己的最后一次被访问的时间, 这个时间可以用于计算对象的空转时间。
参考:
redis系列之------对象的更多相关文章
- redis 系列9 对象类型(字符串,哈希,列表,集合,有序集合)与数据结构关系
一.概述 在前面章节中,主要了解了 Redis用到的主要数据结构,包括:简单动态字符串.链表(双端链表).字典.跳跃表. 整数集合.压缩列表(后面再了解).Redis没有直接使用这些数据结构来实现键值 ...
- 【目录】redis 系列篇
随笔分类 - redis 系列篇 redis 系列27 Cluster高可用 (2) 摘要: 一. ASK错误 集群上篇最后讲到,对于重新分片由redis-trib负责执行,关于该工具以后再介绍.在进 ...
- redis 系列14 有序集合对象
一. 有序集合概述 Redis 有序集合对象和集合对象一样也是string类型元素的集合,且不允许重复的成员.不同的是每个元素都会关联一个double类型的分数.redis正是通过分数来为集合中的成员 ...
- Redis系列(二):Redis的数据类型及命令操作
原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...
- Redis系列--内存淘汰机制(含单机版内存优化建议)
https://blog.csdn.net/Jack__Frost/article/details/72478400?locationNum=13&fps=1 每台redis的服务器的内存都是 ...
- Redis系列(一)StackExchange.Redis的使用
Redis系列(一)StackExchange.Redis的使用 一.DLL安装 用NuGet搜索StackExchange.Redis,然后下载就可以. ConnectionMultiplexer对 ...
- Redis 系列(04-2)Redis原理 - 内存回收
目录 Redis 系列(04-2)Redis原理 - 内存回收 Redis 系列目录 1. 过期策略 1.1 定时过期(主动淘汰) 1.2 惰性过期(被动淘汰) 1.3 定期过期 2. 淘汰策略 2. ...
- Redis 系列(02)数据结构
目录 Redis 系列(02)数据结构 Redis 系列目录 1. String 1.1 基本操作 1.2 数据结构 1.3 Redis数据存储结构 2. Hash 2.1 基本操作 2.2 数据结构 ...
- Redis系列-存储hash主要操作命令
Redis系列-存储篇hash主要操作函数小结 hash是一些列key value(field value)的映射表.常常用其存储一些对象实例.相对于把一个对象的各个字段存储为string,存储为ha ...
随机推荐
- 用.NET做动态域名解析
用.NET做动态域名解析 动态域名解析,或DNSR,通常用于解析IP地址经常变化的域名.电信网络提供了公网IP,给广大程序员远程办公.内容分享等方面带来了极大的便利.但公网IP是动态的,它会经常变化, ...
- Vue2.0+ElementUI实现表格翻页的实例
参考地址: https://www.cnblogs.com/zhouyifeng/p/7706815.html
- IntelliJ IDEA 如何在同一个窗口创建多个项目--超详细教程
一.IntelliJ IDEA与Eclipse的区别 二.在同一个窗口创建多个项目 1.打开IntelliJ IDEA,点击Create New Project 2.Java Enterprise-- ...
- Windows和Linux下scrapy框架的安装
windows下安装: 1.安装Anaconda环境管理工具 也可以使用pip安装,值得注意的是如果你使用的是pip安装,你需要解决相应的包依赖(解决依赖一般会让你怀疑人生.怀疑scrapy,建议还是 ...
- Locomotion和Navigation的区别
Locomotion和navigation两者都是移动.漫游的意思.但是locomotion是一个比navigation更大的概念,它指的是所有的第一人称视角的变换(first-person moti ...
- K8s 从懵圈到熟练 – 集群网络详解
作者 | 声东 阿里云售后技术专家 导读:阿里云 K8S 集群网络目前有两种方案:一种是 flannel 方案:另外一种是基于 calico 和弹性网卡 eni 的 terway 方案.Terway ...
- 项目二:企业级java电商网站开发(服务端)
声明:项目源于网络,支持正版教程,学习使用,仅记录在此 项目介绍 企业级java电商网站开发(服务端),模块划分:用户管理,商品管理,商品品类管理,订单管理,订单详情管理,购物车管理,收货地址管理,支 ...
- request.getAttribute()和request.getParameter()
request.getParameter()取得是通过容器的实现来取得通过类似post,get等方式传入的数据,request.setAttribute()和getAttribute()只是在web容 ...
- mpvue 星星打分组件
上图: <template> <div class="container"> <div v-for="(star,index) in sta ...
- 乱七八糟的学习资料汇总(python3.x,pyqt,svn,git)
入门涉猎资料: python3.6.3中文文档:https://www.runoob.com/manual/pythontutorial3/docs/html/interpreter.html pyt ...