当前位置: 首页 > news >正文

Redis EmbeddedString

前言

Redis 写入键值对时,首先会先创建一个 RedisObject 对象来存储 Value。
如果写入的 Value 是字符串,那么 Redis 会再根据写入的字符串长度,来创建对应的 sdshdr 来存储字符串,最后把 RedisObject 的 ptr 指针指向 sdshdr。
我们来分析下这个过程,首先创建 RedisObject 需要分配一次内存,创建 sdshdr 又需要再分配一次内存。
由此可见,如果 RedisObject 和 sds 分开存储的话,需要多分配一次内存,内存碎片化的概率也会增加。
Redis 本着节省内存的原则,还可以做出哪些优化呢?

EmbeddedString

先回顾一下 RedisObject 结构,前三个属性合计占用 4 字节,refcount 占用 4 字节,ptr 指针占用 8 字节,合计 16 字节。

typedef struct redisObject {unsigned type:4;unsigned encoding:4;unsigned lru:LRU_BITS;int refcount;void *ptr;
} robj;

Redis 默认使用 jemalloc 内存分配器,分配的内存必须是 2 的幂次方大小,比如你要申请 5 字节,jemalloc 会给你分配 8 字节;你要申请 10 字节,jemalloc 会分配 16 字节。
基于这个规则,Redis 就想,能不能创建 RedisObject 的同时就分配多一点内存,好存储接下来的字符串呢?当然可以,那申请多大合适呢?首先肯定要是 2 的幂次方数,32 字节有点太小了,因为 sdshdr8 头部就占用了 3 字节,再加上一个 ‘\0’ 结尾符,真正留给字符串的空间就剩 12 字节了,显然不实用,很容易溢出。
32 不够,那只能再往上加了,64 字节,可以存储 44 字节的字符串,基本够用了。恰巧在 x86 架构下,CPU 缓存行的大小一般也是 64 字节,刚好可以完整加载。

所以,现在我们得出一个结论,如果写入的字符串长度在 44 以内,那么就可以在创建 RedisObject 时直接申请 64 字节,然后把 sds 直接挨着 RedisObject 末尾写入,这样就可以避免再分配一次内存,内存的碎片率也能得到优化。

我们看看 Redis 具体是怎么做的,创建字符串对象的方法是createStringObject()

#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)return createEmbeddedStringObject(ptr,len);elsereturn createRawStringObject(ptr,len);
}

常量 OBJ_ENCODING_EMBSTR_SIZE_LIMIT 的值刚好就是 44,这证明了我们的猜想。如果字符串长度超过了 44,Redis 也只能分配 sds 空间,单独存储字符串了,对应的方法是createRawStringObject()

这种和 RedisObject 存储在一起的字符串,Redis 给它取名叫 EmbeddedString,创建的方法是createEmbeddedStringObject()

robj *createEmbeddedStringObject(const char *ptr, size_t len) {robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1);struct sdshdr8 *sh = (void*)(o+1); // sh 指向 RedisObject末尾 即sdshdr开始位置o->type = OBJ_STRING; // 对外类型还是 stringo->encoding = OBJ_ENCODING_EMBSTR; // 区别于普通sds,这里的编码类型是8o->ptr = sh+1; // ptr 指向sdshdr末尾 即字符串开始位置o->refcount = 1;// 设置lru时钟if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;} else {o->lru = LRU_CLOCK();}// 设置sdshdr头sh->len = len;sh->alloc = len;sh->flags = SDS_TYPE_8;if (ptr == SDS_NOINIT)sh->buf[len] = '\0';else if (ptr) {memcpy(sh->buf,ptr,len);sh->buf[len] = '\0';} else {memset(sh->buf,0,len+1);}return o;
}

创建 EmbeddedString 的步骤如下:

  • 先分配内存,大小是 RedisObject 大小 + sdshdr8 大小 + 字符串长度 + 1个’\0’字符的长度
  • sh 指针指向 sdshdr 的起始位置
  • RedisObject->ptr 指针指向字符数组的起始位置,在介绍 sds 的说过了,指针左移一位就能读到 flags
  • 给 RedisObject 对象设置 lru 时间戳
  • 设置 sdshdr 头数据

尾巴

当我们向 Redis 写入 string 数据时,Redis 首先要创建 RedisObject 分配一次内存,然后再创建 sds 时又要二次分配内存,这样不仅浪费内存,还会增加碎片化率。Redis 结合 jemalloc 的分配策略,以及 x86 架构下的缓存行大小,决定如果写入的字符串长度较小,就一次直接申请 64 字节的内存,剩下 44 字节的长度用来存储字符串,这种字符串的存储方式也被称作 嵌入式字符串。

相关文章:

Redis EmbeddedString

前言 Redis 写入键值对时&#xff0c;首先会先创建一个 RedisObject 对象来存储 Value。 如果写入的 Value 是字符串&#xff0c;那么 Redis 会再根据写入的字符串长度&#xff0c;来创建对应的 sdshdr 来存储字符串&#xff0c;最后把 RedisObject 的 ptr 指针指向 sdshdr。 …...

SpringMVC之WEB-INF下页面跳转@ModelAttributeIDEA tomcat控制台中文乱码问题处理

WEB-INF下页面跳转 ModelAttribute来注解非请求处理方法 用途&#xff1a;预加载数据&#xff0c;会在每个RequestMapping方法执行之前调用。 特点&#xff1a;无需返回视图&#xff0c;返回类型void IDEA tomcat控制台中文乱码问题处理 复制此段代码&#xff1a;-Dfile.e…...

利用ChatGPT练习口语

目录 ChatGPT 这两天发布了一个激动人心的新功能&#xff0c;App端&#xff08;包括iOS和Android&#xff09;开始支持语音对话以及图片识别功能。 这两个功能一如既往的优先开放给Plus用户使用&#xff0c;现在将App更新到最新版本&#xff0c;就能体验。 为什么说激动人心&a…...

【Django 01】环境搭配与项目配置

1. 介绍 https://github.com/Joe-2002/sweettalk-django4.2#readme Django 是一个使用 Python 编写的开源 Web 应用程序框架&#xff0c;它提供了一套用于快速开发安全、 可扩展和高效的 Web 应用程序的工具和功能。Django 基于 MVC&#xff08;Model-View-Controller&#xf…...

PyCharm配置运行参数

...

ChatGPT AIGC 实现Excel 交叉查找 Index+match 函数

行与列交叉多条件查找需求如下: 这个需求要使用Excel中最经典的组合函数Index+match函数。 函数公式可以交给ChatGPT AIGC来实现。 Prompt: 有一个表格A列为品牌,B列为月份,C列为销量,61行数据,请写出Excel函数公式根据E3单元格的品牌与F2单元格的月份查找对应的销量,…...

【前端学习】—多种方式实现数组拍平(十一)

【前端学习】—多种方式实现数组拍平&#xff08;十一&#xff09; 一、数组拍平 数组拍平也叫数组扁平化、数组拉平、数组降维&#xff0c;指的是把多维数组转化为一维数组。 二、使用场景 复杂场景下的数据处理&#xff08;echarts做大屏数据展示&#xff09; 三、如何实…...

智慧远程医疗服务:从零开始搭建互联网医院APP

互联网医院APP作为远程医疗服务的一部分&#xff0c;正在为患者和医生带来更便捷的医疗体验。本文将探讨如何从零开始构建一个互联网医院APP&#xff0c;包括关键步骤、技术要点和挑战。 一、确定项目目标和范围 在开始之前&#xff0c;您需要明确定义您的互联网医院APP的目标…...

ADAS可视化系统,让自动驾驶更简单 -- 入门篇

随着车载芯片的升级、技术的更新迭代&#xff0c;可视化ADAS逐渐变成汽车的标配走入大家的生活中&#xff0c;为大家的驾车出行带来切实的便捷。那么你了解HMI端ADAS的实现过程吗&#xff1f;作为ADAS可视化系统的入门篇&#xff0c;就跟大家聊一聊目前较常见的低消耗的一种ADA…...

探索低代码技术

低/无代码的高速发展&#xff0c;属于软件市场的选择&#xff0c;相较于传统编写代码的开发方式&#xff0c;低/无代码开发效率高、投入成本低、技术门槛也更低&#xff0c;未来更多软件应用将使用低/无代码技术完成&#xff0c;这也是趋势。 身为开发人员经常需要花大量时间在…...

头歌的数据库的第二次作业的答案

目录 MySQL-视图 第1关&#xff1a;创建所有保险资产的详细记录视图 第2关&#xff1a;基于视图的查询 MySQL数据库 - 连接查询 第1关&#xff1a;内连接查询 第2关&#xff1a;外连接查询 第3关&#xff1a;复合条件连接查询 MySQL数据库 - 子查询 第1关&#xff1a;…...

基于R329 SOC智能音响开发编译环境搭建

R329智能音响开发编译环境搭建 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务, R329编译命令 source build/envsetup.sh lunch make -j4 pack 编译工程选择 baidu_panshan...

libplctag开源库的API介绍

文章目录 1 开源库概要2 API介绍2.1 Tag Model&#xff08;标签模型&#xff09;2.2 Status Codes&#xff08;状态码&#xff09;2.3 Versions and Checking Library Compatibility&#xff08;版本和检查库的兼容性&#xff09;2.4 Tag Life Cycle&#xff08;标签生命周期&a…...

智能化安全巡更巡查系统—提升安全管理效率

传统的巡检都是手工完成&#xff0c;记录、拍照&#xff0c;回到办公室打印表单再交给作业队伍整改&#xff0c;再去现场核实复查&#xff0c;流程繁琐&#xff0c;效率低。而且大部分工地为了减少麻烦&#xff0c;人员往往都是口头沟通&#xff0c;存在很大质量风险&#xff0…...

SAP MM学习笔记36 - 释放支付保留的发票

SAP中&#xff0c;请求书照合之后&#xff0c;发现不一致&#xff0c;就会支付保留。 支付保留&#xff0c;可以参考如下文章。 SAP MM学习笔记34 - 请求书照合中的支付保留&#xff08;发票冻结&#xff09;_东京老树根的博客-CSDN博客 当然发现不一致之后&#xff0c;如果不…...

MySQL数据库的ID列添加索引

要为MySQL数据库的ID列添加索引&#xff0c;可以使用以下语法&#xff1a; ALTER TABLE table_name ADD INDEX index_name (id);其中&#xff0c;table_name是要添加索引的表名&#xff0c;index_name是索引的名称&#xff0c;id是要添加索引的列名。 例如&#xff0c;如果要…...

LuaJIT编写的解析十六进制数据

以下是使用LuaJIT编写的解析十六进制数据并将uint16转换为JSON的示例代码&#xff1a; local ffi require("ffi") local bit require("bit") local cjson require("cjson")-- 定义结构体 ffi.cdef[[typedef struct {uint16_t value;} uint16…...

【SA8295P 源码分析 (一)】09 - XBL Loader 加载 QSEE、SEC、CPUCPFW、QHEE、APPSBL过程分析

【SA8295P 源码分析】09 - XBL Loader 加载 QSEE、SEC、CPUCPFW、QHEE、APPSBL过程分析 一、QSEE二、SEC三、CPUCPFW四、QHEE五、APPSBL系列文章汇总见:《【SA8295P 源码分析 (一)】系统部分 文章链接汇总 - 持续更新中》 本文链接:《【SA8295P 源码分析 (一)】09 - XBL Load…...

封装一个Element-ui生成一个可行内编辑的表格(vue2项目)

这个封装的是一个供整个项目使用的表格,可多次复用.放在一个全局使用的公共组件文件下. 大致功能介绍,封装自定义指令,点击获得焦点,显示输入框,失去焦点显示文本内容,类型是字典决定类型,图片可以显示图片名还是上传图片 子组件 <script> export default {props: {//生…...

hanniman 1v1 咨询

‍ 一共4种可选方案&#xff0c;3个To C&#xff08;面向AI产品经理的职业规划诊断、求职内推套餐、模拟面试&#xff09;&#xff0c;1个To B&#xff08;面向AI企业/投资机构/券商等&#xff09;。 方案A&#xff1a;职业规划诊断 适合人群&#xff1a;AI产品经理 or 想转型A…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...