Redis-如何减少修改字符串带来的内存分配过程消耗-深入理解

Redis的字符串对象采用简单动态字符串(SDS)实现,通过空间预分配和惰性空间释放策略减少修改字符串带来的内存分配消耗。空间预分配在字符串增长时提供额外未使用空间,当len小于1MB时,free=len;大于1MB时,free=1MB。惰性空间释放则在字符串缩短时不立即释放,而是保留作为后续增长操作的缓存空间,降低内存重分配频率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Redis字符串的特点

  • 已知Redis的键值对的字符串对象,值也可以是字符串对象,值还可以是列表对象、哈希对象、集合对象、有序集合对象总共这五种对象。
  • Redis的底层实现语言是经典的C语言,Redis的字符串定义与C语言的字符串定义有一些区别
    – 1、C语言的字符串对象是以空字符结尾的字符类型数组,有多少个字符该数组就是多大的
    – 2、Redis使用的是简单动态字符串(SDS, simple dynamic string)的抽象类型,SDS除了用来保存Redis的字符串对象之外,还可以用作缓冲区。

SDS的数据结构定义如下:

strcut sdshdr{
	int len;//用来保存数组中已使用字节的数量=SDS所保存的字符串的长度
	int free;//用来保存数组中未使用字节的数量
	int buf[];//字节数组,用来保存字符串。大小=len + free
}

SDS的结构用图像表示如下,以保存字符串"Redis"的一个SDS为例:
SDS示例

  • 从中可以看出,free=0,表示该SDS的未使用空间大小为0;
  • len=5,表示SDS的保存的字符串的大小为5字节;
  • buf的属性是一个char类型的数组,其中保存了如上所示的字符,0个未使用字符空间,还要’结尾处的/0‘空字符。
  • 如果要获取该SDS保存的字符串的长度,不用遍历字符串,直接使用len的值就行。获取长度方便,就能有效防止缓冲区溢出的风险,还能减少修改字符串(如拼接等操作)带来的内存重分配资源消耗

2、SDS如何实现减少修改字符串带来的内存重分配

结论:SDS使用空间预分配和惰性空间释放两种机制来避免标题所示问题

内存重分配:字符串拼接可能带来缓冲区溢出,字符串缩短可以造成内存泄露,这就需要对内存空间进行重分配,这种操作涉及到的算法复杂,可以需要执行系统级别的调用,所需要的资源和时间比较多,要尽量避免,可以使用空间换时间的策略。

(1)空间预分配

当对SDS的API对SDS进行修改,需要对SDS进行空间扩展的时候,会带来两个空间的扩展:所必须的字符串空间,额外的未使用空间

  • len的长度<1MB时,分配的未使用空间大小=len
  • len的长度>=1MB时,分配的未使用空间大小=1MB
  • 也就是len<1MB的时候free=len,大于的时候free=1MB
    通过空间预分配策略,Redis可以减少连续执行字符串增长操作所需要的内存重分配次数。
//示例:
sdscat(s,"Tutorial");//将s和"Tutorial"字符串拼接

对标题1的SDS执行以上程序时,因为未使用字符串空间不够,将执行一次内存重分配操作:len修改为拼接之后的大小并填入数据,free变为13字节。
在这里插入图片描述
如果再次执行上述拼接代码,free空间够用,将不会产生内存重分配。

(2)惰性空间释放

惰性空间释放针对优化SDS的字符串缩短操作,当SDS的API需要缩短SDS所保存的字符串的时候,并不一定要立刻进行内存重分配来释放空闲出来的字节

  • 将释放出来的字节转换为空闲字节,同时更新free属性的大小
  • 此操作能避免缩短字符带来的内存重分配操作,还为可能的增长操作带来了缓存的空间

参考资料:<Redis设计与实现>第一章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值