文章目录

      • 核心比喻:一个可以伸缩的水瓶
      • 场景一:创建一个新字符串
      • 场景二:追加字符串(触发“空间预分配”)
      • 场景三:再次追加字符串(利用空闲空间)
      • 场景四:缩短字符串(惰性空间释放)
      • 总结

我们用一个非常形象的比喻和几个实际的例子,来彻底搞懂 lenalloc 这两个概念。

核心比喻:一个可以伸缩的水瓶

想象一下,Redis 的一个字符串(SDS)就是一个“智能水瓶”,而 sdshdr 就是瓶身上的刻度标签。

  • len (length): 代表瓶子里当前装了多少水。这是字符串的实际、有效长度。
  • alloc (allocation): 代表这个瓶子的最大容量。这是系统为这个字符串总共分配了多大的内存空间(不含头部和末尾的 \0)。
  • 空闲空间 (free space): alloc - len,就代表瓶子里还能装多少水,也就是预留的空闲内存。

关键点:瓶子的容量 (alloc) 永远大于或等于瓶子里的水量 (len)。

这个设计的核心目的,就是避免频繁地“换瓶子”。因为“换瓶子”(内存重分配)是一个非常耗时的操作。如果每次只加一滴水,你都要去找一个大小刚刚好的新瓶子,效率会非常低下。


场景一:创建一个新字符串

当你执行 SET mykey "hello" 时,Redis 创建了一个 SDS 字符串。

  • 字符串 “hello” 的长度是 5。
  • Redis 内部会创建一个 sdshdr 和一块内存来存放它。假设它选择 sdshdr8 类型(头部占3字节)。
  • 为了效率,它可能不会只分配刚刚好的5字节,但我们为了简化,先假设它就是这么做的。

内存状态:

  • len = 5 (瓶里有5个单位的水)
  • alloc = 5 (瓶子总容量是5)
  • 内存布局大致如下:
    [sdshdr8: len=5, alloc=5] ['h','e','l','l','o','\0']
    
    此时,空闲空间 alloc - len 为 0。瓶子是满的。

场景二:追加字符串(触发“空间预分配”)

现在,我们来追加内容,执行 APPEND mykey " world"

  1. 检查空间:

    • 要追加的字符串 " world" 长度为 6。
    • API 首先检查空闲空间:alloc(5) - len(5) = 0
    • 0 < 6,空间不够!需要“换个大瓶子”(重新分配内存)。
  2. 执行空间预分配(The Magic):

    • 新的字符串总长度将是 len(5) + 6 = 11
    • Redis 不会只分配 11 字节的新空间,它会想:“你既然开始追加了,很可能等下还会再追加。”
    • 于是它启动空间预分配策略:新分配的容量 alloc 会是 新长度的两倍 (在字符串总长小于1MB时)。
    • 新的 alloc = 11 * 2 = 22
    • Redis 会申请一块能容纳 22 个字符的新内存空间,并把旧内容 “hello” 和新内容 " world" 拷贝进去。

内存状态更新:

  • len = 11 (现在瓶里有11个单位的水)
  • alloc = 22 (但瓶子的总容量是22!)
  • 内存布局大致如下:
    [sdshdr16: len=11, alloc=22] ['h','e','l','l','o',' ','w','o','r','l','d','\0', ...11 bytes free... ]<---- len = 11 ----> <---- free = 11 ----><----------------- alloc = 22 ----------------->
    
    现在,alloc(22) - len(11) = 11,我们有 11 个字节的空闲空间

场景三:再次追加字符串(利用空闲空间)

我们继续追加,执行 APPEND mykey "!!!"

  1. 检查空间:

    • 要追加的 “!!!” 长度为 3。
    • API 检查空闲空间:alloc(22) - len(11) = 11
    • 11 >= 3,空间足够!不需要重新分配内存!
  2. 原地修改:

    • 直接在 buf 的末尾把 “!!!” 写进去。
    • 只更新头部的 len 字段。

内存状态更新:

  • len = 11 + 3 = 14 (水变多了)
  • alloc = 22 (瓶子还是那个瓶子,容量没变)
  • 内存布局大致如下:
    [sdshdr16: len=14, alloc=22] ['h','e','l','l','o',' ','w','o','r','l','d','!','!','!','\0', ...8 bytes free... ]<------ len = 14 ------> <---- free = 8 ----><------------------- alloc = 22 ------------------->
    
    这个操作非常快,因为它避免了最耗时的内存分配和数据拷贝。

场景四:缩短字符串(惰性空间释放)

现在,我们把这个 key 的值改成一个很短的字符串,执行 SET mykey "Hi"

  • Redis 会直接用 “Hi” 覆盖掉 buf 开头的内容。
  • 然后,它只会更新 len 字段。

内存状态更新:

  • len = 2 (水变得很少)
  • alloc = 22 (但瓶子还是那个大瓶子!)
  • 内存布局大致如下:
    [sdshdr16: len=2, alloc=22] ['H','i','\0','l','o',' ','w','o','r','l','d', ...garbage data..., ...free space... ]<len=2> <----------------- free = 20 -----------------><------------------- alloc = 22 ------------------->
    
  • 这被称为惰性空间释放。Redis 不会立即把多余的 20 字节空间还给操作系统。它会保留这些空间,因为你可能马上又会执行 APPEND 操作,这样就又可以利用上这些预留空间了。

总结

lenalloc 的设计哲学,是典型的用空间换时间的思想。

  • len 提供了 O(1)O(1)O(1) 时间复杂度的长度获取能力,并且是二进制安全的基础。
  • alloc 配合空间预分配惰性释放策略,极大地减少了内存重分配的次数,这是 Redis 字符串追加(APPEND)操作如此高效的关键所在。它将多次可能发生的、耗时的内存操作,均摊到了一次操作中。

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

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

相关文章

在Linux下访问MS SQL Server数据库

Linux作为一个免费的Unix类操作系统&#xff0c;以其开放性源代码、多任务、X window等特点为众多的用户所采用&#xff0c;并有很多企业采用Linux来作为其内部网的全功能服务器(WWW&#xff0c;FTP&#xff0c;Email、DNS)。企业的内部网不仅要提供文本信息的访问&#xff0c;…

计算机视觉-OpenCV

一下载第三方库opencv-python3.4.18.65opencv-contrib-python3.4.18.65import cv2 # 读取的格式是BGR numpy import numpy as np# 读取图片 a cv2.imread(generated_image.jpg) # 读取图片 print(a) # NumPy数组&#xff0c;其中存储了读取的图像文件的像素值。cv2.imshow…

解决GitHub无法打开

找到下图文件&#xff0c;用记事本打开 在最下方粘贴如下代码140.82.113.4 github.com 20.205.243.166 github.com 140.82.112.4 github.com 151.101.1.6 github.global.ssl.fastly.net 185.199.108.153 assets-cdn.github.com 185.199.109.153 assets-cdn.github.com 185.199.…

AWS VPC Transit Gateway 可观测最佳实践

AWS VPC Transit Gateway 介绍 Amazon VPC Transit Gateway 是一个网络传输中心&#xff0c;用于互连虚拟私有云 (VPCs) 和本地网络。随着您的云基础设施在全球扩展&#xff0c;区域间对等互连使用 AWS 全球基础设施将中转网关连接在一起。 AWS 数据中心之间的所有网络流量都在…

WeakRef的作用和使用

文章目录WeakRef的作用和使用使用 WeakRef 避免强引用&#xff1a;原理与实践一、WeakRef 的核心特性二、WeakRef 与强引用的对比三、WeakRef 的使用场景与示例1. 非关键数据缓存&#xff08;避免缓存导致内存泄漏&#xff09;2. 跟踪对象生命周期&#xff08;不干扰回收&#…

【华为机试】332. 重新安排行程

文章目录332. 重新安排行程题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;解题思路核心思路算法流程图欧拉路径原理DFS回溯机制字典序优化策略复杂度分析算法实现要点完整题解代码332. 重新安排行程 题目描述 给你一份航线列表 tickets &#xff0c;其中 tic…

通信算法之300:CRC表生成方式-CRC8、CRC16、CRC32-输入字节

"CRC表的MATLAB生成代码"生成的查找表可以用于快速计算 CRC 值&#xff0c;通过查表法可以显著提高 CRC 计算效率&#xff0c;尤其适用于需要处理大量数据的场景。下面是一个生成 CRC 查找表&#xff08;CRC Table&#xff09;的 MATLAB 代码&#xff0c;该代码可以根…

国内使用 npm 时配置镜像源

在国内使用 npm 时&#xff0c;由于网络限制可能会遇到下载速度慢或连接超时的问题。通过设置国内镜像源&#xff0c;可以显著提升下载速度和稳定性。以下是常用的国内 npm 镜像源及其配置方法。 查询当前使用的镜像源 npm get registry 设置为淘宝镜像源 npm config set reg…

一篇文章入门TCP与UDP(保姆级别)

&#x1f433;第一部分&#xff1a;什么是TCP和UDP? 先给结论&#xff1a;TCP 和 UDP 都是传输层协议&#xff0c;负责把数据从一台电脑 “搬” 到另一台电脑&#xff0c;但它们的 “搬运风格” 完全不同 &#x1f4e6; 比喻&#xff1a;TCP 像 "打电话"&#xff…

2024年测绘程序设计比赛--空间探索性分析(数据为2025年第三次模拟数据)

想要在2026年参加这个比赛的&#xff0c;可以加入小编和其它大佬所建的群242845175一起来备赛&#xff0c;为2026年的比赛打基础&#xff0c;也可以私信小编&#xff0c;为你答疑解惑一、读写文件 internal class Read {public static List<Point> pts new List<Poin…

力扣 hot100 Day68

84. 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 class Solution { public:int largestRectangleArea(vector<int>&…

生成式AI时代,Data+AI下一代数智平台建设指南

DataAI下一代数智平台建设指南一、生成式AI时代的五大数据挑战二、驱动DataAI平台建设的核心要素主动选择&#xff1a;构建竞争壁垒被动应对&#xff1a;解决现有痛点三、DataAI平台的六大关键能力四、腾讯云DataAI产品方案与实践1. 数据与AI协同层2. 开发与治理层3. 存储与计算…

FPGA学习笔记——SPI通讯协议简介

目录 一、SPI通讯协议简介 二、SPI物理层 三、SPI协议层 1.通讯模式 &#xff08;一&#xff09;模式零 &#xff08;二&#xff09;模式一 &#xff08;三&#xff09;模式二 &#xff08;四&#xff09;模式三 2.通讯流程 一、SPI通讯协议简介 SPI&#xff08;Seria…

JavaScript核心概念解析:从基础语法到对象应用

导语&#xff1a;本文系统梳理JavaScript的核心知识框架&#xff0c;适用于编程入门学习者。内容涵盖基础语法、数据类型、函数应用及内置对象&#xff0c;帮助读者构建清晰的JS知识体系。一、语言基础与执行原理浏览器执行机制渲染引擎&#xff1a;解析HTML/CSS&#xff08;如…

在 Kotlin 中使用函数类型和 lambda 表达式

参考官方文档: https://developer.android.google.cn/codelabs/basic-android-kotlin-compose-function-types-and-lambda?hl=zh-cn#0 1、 将函数存储在变量中 作为一种一级结构,函数也属于数据类型,因此,可以将函数存储在变量中、将函数传递到函数,以及从函数返回函数…

计算机硬件组成原理

&#x1f9e0; 一、计算机的硬件组成&#xff1a;五大核心部件 根据“冯诺依曼体系结构”&#xff0c;现代计算机主要由这 5大部分组成&#xff1a;部件作用通俗解释1️⃣ 运算器&#xff08;ALU&#xff09;负责算术和逻辑运算会加减乘除和做判断的“计算工厂”2️⃣ 控制器&a…

告别 window.open,拥抱全新浮窗体验!

深入了解 Document Picture-in-Picture API&#xff0c;并对比 Modal 的最佳使用场景在前端开发中&#xff0c;我们经常会遇到这样的需求&#xff1a;弹出一个浮动窗口来显示一些实时信息、工具栏或视频内容。过去我们会用 window.open()&#xff0c;后来越来越多的开发者倾向于…

Python爬虫实战:研究weiboSpider技术,构建新浪微博数据采集系统

1. 引言 1.1 研究背景 在信息时代,社交媒体已成为人们获取信息、表达观点的重要渠道。微博作为其中的典型代表,拥有庞大的用户群体和活跃的内容生态。截至 2023 年底,微博月活跃用户数已超过 5.8 亿,日均发博量达数千万条,数据涵盖社会热点、公众情绪、消费偏好等多维度…

HashMap初始化容量为10,还未添加数据时,它的实际容量是多少?

在Java中&#xff0c;当使用 new HashMap<>(10) 初始化一个容量为10的 HashMap 但尚未添加任何数据时&#xff0c;其实际容量&#xff08;底层数组的长度&#xff09;不是10&#xff0c;而是16。原因如下&#xff1a;关键机制解析&#xff1a;容量必须是2的幂HashMap要求…

前端开发:CSS(2)—— 选择器

前面我们初步学习了CSS&#xff0c;对其有了基本的认识。下面我们来具体学习CSS中的选择器。 目录 选择器的种类 1.基础选择器 &#xff08;1&#xff09;标签选择器 &#xff08;2&#xff09;类选择器 &#xff08;3&#xff09;id选择器 &#xff08;4&#xff09;通…