redis面试(一)String底层剖析

前言

今天开始更新一些redis相关的知识点,初步计划是redis的数据类型,以及redis分布式锁
本章节主要是redis的String类型

字符串SDS

一般情况下我们认为的redis 字符串就是String,但是我这边要说的是底层String类型。

redis底层是C语言,但是C语言中的String有一定的缺陷,所以redis开发了一个自己的字符串类型 SDS 也就是simple dynaic string,专门的数据结构,保证字符串的完整性 动态字符串

c语言中的字符串是 r,e,d,i,s,\0 这种n+1的形式存储的,读取的时候一个个的读取,一直到 \0 这个数据
获取字符串长度的时候,还要遍历一遍

redis sds的字符串类型如下

struct sdshdr {int len;	// 已使用字节数= 字符串长度int free; 	// 未使用字节数char buf[];	// 字符串本身内容
}

比如:
sdshdr
free=0
len=5
buf-> [r,e,d,i,s,\0]

c字符串里规定除了末尾可以有一个\0空字符以外,内容里不能包含空字符,否则读到空字符就认定这个字符串结束了,所以导致c字符串只能保存文本,不能保存图片和音视频一类的二进制数据

二进制问题

re\0di\0s
re di s
如果你要是在内容里包含了很多空字符的话,你就不是二进制安全的了
但是sds实现了二进制安全,而且允许内容里包含\0,这是为什么呢,因为sds里有一个len,他是根据len来读取指定字节数量的字符的,而不是根据\0来判断字符串是否结束了,这是一个很关键的优化,通过这个就可以实现二进制安全了
但是redis还是遵守了末位是\0的c规范,这样保存的字符串,就可以复用c语言的一些函数了,因为c语言函数是这么规定的

c语言原生字符串,strlen,获取字符串长度,遍历,O(n),二进制不安全的,对于二进制数据来说,图片、视频、音频、压缩文件,这种数据都是以一大堆的二进制串来存储的,里面肯定会有很多\0空字符,对于c语言来说,读取的时候,一定要按照\0来截断,肯定不行的

二进制不安全,原生的c语言字符串没法安全的存储二进制数据

redis里面的sds,他里面有两个关键的字段,len和free,buf = [] 跟c语言没太大差别,len和free很厉害,free的作用,我们还没讲,len有2个作用,直接读取len,strlen,O(1),读取buf里的数据,不是遍历看到\0就停止

根据len读取指定字节数量的buf数字的内容,形成一个完整的内容,对于我们来说,redis里的sds存储二进制的数据,图片、音视频,就算buf里包含了很多\0空字符,根据len来读取,不是根据\0来截断,redis sds可以实现二进制安全性,安全的保存二进制数据

避免缓冲区溢出

redis和spark两个字符串,在内存地址里,连续的存储在了一起
[r,e,d,i,s,\0,s,p,a,r,k,\0]

str = redis

strcat(str, sentinel) -> 插入忘记了给sentinel字符串分配内存空间

c语言原生字符串可能搞出缓冲区溢出的问题,那就是说,r,e,d,i,s,s,p,a,r,k,连续两个字符串,redis和spark,结果我们要是用c语言的strcat函数,搞了一个strcat(str, ‘sentinel’),想要把sentinel拼接到redis字符串后面去,又忘了给sentinel提前分配内存空间,就会导致,r,e,d,i,s,s,e,n,t,i,n,e,l,直接覆盖掉spark了,这就是缓冲区溢出
[r,e,d,i,s,\0,s,e,n,t,i,n,e,l,\0]

sds(free=0,len=5,buf[r,e,d,i,s,\0]) -> sds(free=13,len=13,buf[r,e,d,i,s,s,e,n,t,i,n,e,l,\0])

sds会自动检查字符串扩容空间是否足够,不够就扩容空间,扩容完毕了再修改字符串的内容,比如sdscat就是这样的拼接字符串的函数,比如一开始sds的free=0,len=5,buf=redis,但是现在你要扩容加上sentinel了,此时就会先扩容,free=13,len=13,buf=redissentinel

内存预分配

除了扩容,他还会额外的给13个自己的free空间

c字符串在拼接或者截断的时候,要不然就得扩容数组,要不然就是释放空间内存,就是有频繁的内存重分配动作,这个内存重分配是很耗费时间的,涉及到os系统调用,redis频繁修改字符串,频繁内存重分配,那就真的是很尴尬

sds为了避免这种频繁内存重分配的问题,才设计了free,这个free可以实现内存预分配和惰性释放,每次sds的内存空间要进行扩容的时候,扩容完毕后,都会根据一个公式,提前计算出free,预分配一定的内存空间出来

扩容后,sds长度小于1mb,就把free设置为跟len一样,做一个双倍预分配,如果扩容后len大于1mb了,就把free设置为1mb就可以了,毕竟不能无限制的扩容下去,这个预分配后,就是底层c里的数组,留了一定字节数量的空间,但是没有真正使用

这样你后续再修改字符串,直接就用free空间就可以了,避免了频繁重分配内存了

惰性释放

如果缩短一个字符串,那么就会把字符串正常缩短,然后len设置为字符串长度,free就是原长度-现长度,以后如果要增长,还可以用free,如果确实要释放内存空间,sds提供了api来释放,但是他是不会立即释放掉的。而是在过一段时间之后,发现空间不足了,才会释放掉这部分空间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/51145.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【python】python生活管理费系统(源码+论文)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

Scala学习笔记20: Future 和Promise

目录 第二十章 Future 和Promise1- 简介1. Future: 对未来结果的承诺2. Promise: 兑现 Future 的谎言3. Future 和 Promise 的关系: 相辅相成4. 总结 2- 执行上下文1. ExecutionContext 的作用:2. 常见的 ExecutionContext :3. 指定 ExecutionContext :4. 示例:5. 总结:6. 注意…

加载chatglm3模型时出现ValueError: too many values to unpack (expected 2)的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

基于Libero的工程创建

基于Libero的工程创建 第一步:双击进入到工程界面,编写项目详细信息。 Project Name:标识您的项目名称。不要使用空格或保留的Verilog或VHDL关键字。 Project Location:在磁盘上标识您的项目位置。 Description:关于…

Linux系统下安装MySQL

前言: 本篇教程是使用Centos8来进行安装部署,如果使用的Linux系统发行版不同安装部署过程中可能会有差异,相同环境下可以跟着操作流程进行部署。本篇文章的主要目的是为了学习分享使用如有疑问欢迎提出并共同讨论。 1、安装前的准备工作 移除…

Power App学习笔记以及基础项目管理demo

Power App学习笔记以及基础项目管理demo 最近学习了一点Power App,感觉挺有意思。配置式组件开发。浅浅记录一下自己实现的项目管理系统(即Excel数据的增删改查)关于函数的一点皮毛认识。 效果图 筛选数据 编辑 详情 数据源 PowerApp 网…

SpringCloud - Nacos配置中心、命名空间

一、 Nacos配置中心 1、在gulimall-common公共模块添加依赖 <!--服务注册发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--…

为RTEMS Raspberrypi4 BSP添加SPI支持

为RTEMS Raspberrypi4 BSP添加SPI支持 主要参考了dev/bsps/shared/dev/spi/cadence-spi.c RTEMS 使用了基于linux的SPI框架&#xff0c;SPI总线驱动已经在内核中实现。在这个项目中我需要实习的是 RPI4的SPI主机控制器驱动 SPI在RTEMS中的实现如图&#xff1a; 首先需要将S…

day06 项目实践:router,axios

vue组件的生命周期钩子 今天几乎没有讲什么新内容&#xff0c;就是一起做项目&#xff0c;只有一个小小的知识点&#xff0c;就是关于vue组件的生命周期钩子&#xff0c;其中最重要的四个函数—— beforeCreate()&#xff1a;组件创建之间执行 created()&#xff1a;组件创建…

[Meachines] [Easy] Admirer Adminer远程Mysql反向+Python三方库函数劫持权限提升

信息收集 IP AddressOpening Ports10.10.10.187TCP:21,22,80 $ nmap -p- 10.10.10.187 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 7.4p1 Debian 10deb9u7 (protocol 2.0) | ssh-hostkey: | …

前端三大主流框架对比

在现代前端开发中&#xff0c;React、Vue和Angular是三大流行的框架/库。它们各自有独特的优缺点&#xff0c;适用于不同的开发需求和项目规模。下面是对这三者的详细比较&#xff1a; 一、 React 简介&#xff1a; 由Facebook开发和维护&#xff0c;是一个用于构建用户界面…

yolov8标注细胞、识别边缘、计算面积、灰度值计算

一、数据标注 1. 使用labelme软件标注每个细胞的边界信息&#xff0c;标注结果为JSON格式 2. JSON格式转yolo支持的txt格式 import json import os import glob import os.path as osp此函数用来将labelme软件标注好的数据集转换为yolov5_7.0sege中使用的数据集:param jsonfi…

【vue前端项目实战案例】之Vue仿饿了么App

本文将介绍一款仿“饿了么”商家页面的App。该案例是基于 Vue2.0 Vue Router webpack ES6 等技术栈实现的一款外卖类App&#xff0c;适合初学者进行学习。 项目源码下载链接在文章末尾 1 项目概述 该项目是一款仿“饿了么”商家页面的外卖类App&#xff0c;主要有以下功能…

【深度学习】“复杂场景下基于深度学习的卷积神经网络在鸟类多类别识别中的模型设计与性能优化研究“(上)

【深度学习】“复杂场景下基于深度学习的卷积神经网络在鸟类多类别识别中的模型设计与性能优化研究”(上) 大家好 我是寸铁&#x1f44a; 【深度学习】“复杂场景下基于深度学习的卷积神经网络在鸟类多类别识别中的模型设计与性能优化研究”(上)✨ 喜欢的小伙伴可以点点关注 &a…

LangChain-v0.2 构建 PDF 采集和问答系统

PDF 文件通常包含其他来源无法获取的重要非结构化数据。它们可能非常长&#xff0c;而且与纯文本文件不同&#xff0c;通常无法直接输入到语言模型的提示中。 在本中&#xff0c;我们将创建一个可以回答有关 PDF 文件的问题的系统。更具体地说&#xff0c;就是使用文档加载器加…

3033. 修改矩阵

3033. 修改矩阵 题目链接&#xff1a;3033. 修改矩阵 代码如下&#xff1a; class Solution { public:vector<vector<int>> modifiedMatrix(vector<vector<int>>& matrix) {vector<int> maxRows(matrix[0].size());for(int j0;j<matri…

【前端 14】Vue常见指令

Vue常见指令 Vue.js 是一个构建用户界面的渐进式框架&#xff0c;它通过一系列简洁的指令&#xff08;Directives&#xff09;来增强HTML的功能&#xff0c;使得开发者能够更加方便地构建出响应式的Web应用。本文将详细讲解Vue中的几个核心指令&#xff1a;v-bind、v-model、v…

AndroidAOSP定制之关闭某些app的通知

AndroidAOSP定制之关闭某些app的通知 前言&#xff1a; ​ 最近在做AOSP系统定制时发现gms定制好了后&#xff0c;Google应用商店用不了&#xff0c;提示此设备未获得Play保护机制认证&#xff0c;Google应用和服务无法在此设备上运行,查看官方文档和资料&#xff0c;说是由于…

【学习笔记】| 03 - 使用STM32CubeMX新建工程

使用STM32CubeMX新建工程是一个相对直观的过程&#xff0c;主要涉及到选择芯片型号、配置外设、时钟系统、GPIO引脚等&#xff0c;并最终生成工程代码。以下是一个详细的步骤指南&#xff1a; 一、打开STM32CubeMX并新建工程 启动STM32CubeMX&#xff1a; 打开STM32CubeMX软件…

FPGA实验6: 有时钟使能两位十进制计数器的设计

一、实验目的与要求 1.. 熟练掌握使用原理图设计较复杂电路&#xff1b; 2. 学习原理图设计中总线的表示以及使用方法。 二、实验原理 运用Quartus II 集成环境下的图形设计方法设计有时钟使能的两位十进制计数器。进行波形仿真和分析、引脚分配并下载到实验设备上进行功能…