zoukankan      html  css  js  c++  java
  • Redis02:底层:字符串

    底层:字符串

    在redis中除了少数用来打印日志信息的字符串,其他字符串都是以SDS的形式存储的,SDS的全称是simple dynamic string。

    SDS的定义

    SDS的定义如下:

    struct sdshdr{
    	//SDS保存的字符串的长度
    	int len;
    	//buf数组中未使用的字节数量
    	int free;
    	//用于保存字符串的字节数组,可能存在一部分未使用空间
    	char buf[];
    } sdshdr;
    

    下图就是一个存有字符串Redis的SDS:

    free值是5代表数组中有5个字节未被使用,数组中的字符串以空字符结尾,len值代表字符串的真正长度,不包括空字符。存在空字符的好处在于,这样处理后的SDS在底层和c字符串几乎一样,所以可以直接重用一部分C字符串函数库里面的函数。

    与C字符串的对比

    常数复杂度获取字符串长度

    C字符串不记录长度信息,所以为了获取字符串长度就必须遍历整个字符串,这个操作的复杂度为ON,而SDS可以根据len字段立即获得字符串长度,这确保了获取字符串长度不会成为redis的性能瓶颈。

    杜绝缓冲区溢出

    C字符串不记录自身长度可能会导致缓冲区溢出的情况出现,比如在没有考虑分配空间的情况下对字符串进行拼接操作,新生成的字符串可能很大,大到覆盖了周围的有用数据。而SDS在修改时,首先会检查SDS的空间是否满足修改的要求,如果不满足的话会进行空间扩展,不会有溢出问题出现。

    内存分配策略

    C的字符串每次改变时,都会对保存字符串的数组进行一次内存重分配操作,如果是增长字符串就是重分配来扩展空间,这个过程可能产生缓冲区溢出;如果是缩短字符串就是重分配来缩小空间,如果不释放空间就会产生内存泄露。

    内存重分配涉及系统调用,是一个比较耗时的操作,在一般的程序中,不频繁的内存重分配是可以接受的,但是在redis需要的速度比较严苛,为了克服这种缺陷,SDS通过free这个字段来降低内存分配的次数,主要从两个方面改善:

    1、空间预分配:每次增加字符串长度的时候,SDS不会分配一个正好大小的字符数组,而是分配的稍大一点,以便未来的增长操作不会触发内存重分配。

    如果修改SDS后,SDS的len小于1MB,那么此时SDS会分配与len相同的空闲空间,如修改后SDS的len是13字节,那么free也是13字节,整个SDS的buf数组实际长度是13+13+1=27字节。

    如果修改SDS后,SDS的len大于等于1MB,那么程序会分配1MB的未使用空间。

    2、惰性空间释放:当SDS执行缩短操作时,程序不立即使用内存重分配来回收缩短的字节,而是使用free将这些字节的数量记录下来,以备将来使用。SDS也有对应的API来释放真正的未使用空间,不用担心造成空间浪费。

    二进制安全

    C字符串中的字符必须符合某种编码,除了字符串的末尾外字符串内部不能有空字符,这使得C字符串只能保存文本数据。而redis中的SDS是二进制安全的,可以保存非文本数据,它保存的是一系列二进制数据,SDS通过检查len来判断字符串是否结束,所以没有空字符的限制。

    总结:C字符串和SDS对比

  • 相关阅读:
    混合现实开发教程unity2017
    Intro to Airplane Physics in Unity 3D – 2017 and 2018
    Unity Awards 2018最佳资源
    ambiguous
    Unity2018.3全新Prefab预制件系统深入介绍视频教程+PPT+Demo源码
    Android Studio 集成开发工具教学视频 + 项目实战安卓多SDK接入与集成
    Unity下一轮最大的变革-Entity Component System & C# Jobs System
    使用unity开发游戏时如觉得游戏声音太吵,点Mute Audio
    SQL Delta实用案例介绍
    经典批处理实现自动关机(BAT)
  • 原文地址:https://www.cnblogs.com/yinyunmoyi/p/11521158.html
Copyright © 2011-2022 走看看