浅谈Go与习题(三十六)

62 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情

今天来学习下Go常见的习题问题(三十六),也是面试中可能会遇到的,让我们来一起学习吧~

SDS设计

今天来介绍下Redis中的简单动态字符串(simple dynamic string,SDS),下面是sds.h/sdshdr中SDS的结构体:

struct sdshdr {
  // 记录buf数组中已使用字节的数量
  // 等于SDS所保存字符串的长度
  int len;
  
  // 记录buf数组中未使用字节的数量
  int free;
  
  // 字节数组,用于保存字符串
  char buf[];
}

因为SDS遵循以空字符结尾,并且不计算在len长度中,可以用C字符串库中的一些函数,例如printf

SDS 与 C 字符串的区别:

  • C字符串因为没有长度的字段,所以想要获取字符串的长度需要遍历整个数组,时间复杂度为O(N),SDS则直接获取len字段就可以知道字符串长度,时间复杂度为O(1)

  • 避免缓冲区溢出:C字符串由于没有长度的统计,所以每次进行strcat字符串拼接会认为空间是足够的,会导致污染其他内存空间的值,而SDS的空间分配策略就可以避免这个问题的发生

  • 减少修改字符串带来的内存重新分配:由于SDS存在free字段,所以buf数组的长度就不会是len+1,而是加上未使用的内存空间,那么就有空间预分配惰性空间释放两种优化策略

    1. 空间预分配:SDS的API要进行内存扩展的时候,不仅扩展所需要修改的空间,也会分配额外的free空间,取决于len是否小于1MB
    2. 惰性空间释放:SDS 的API要缩短字符串时, 不会立即内存重分配来回收缩短后多出来的字节,而是使用 free 属性将这些字节的数量记录起来, 当然也可以直接使用API释放未使用的空间,防止内存浪费

总结

今天浅谈了Go的习题(三十六),参考资料《redis设计与实现》,接下来会继续分享其他的习题的相关知识,对于一个刚入门的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!