alloc 表示实际分配的空间 flags 低三位表示类型,高五位未使用 buf 存储的字符 因此sds示意图就是这样的: 那么redis为什么要这么设计呢,出于以下几点考虑: 降低获取字符串长度的复杂度...避免缓冲区溢出,当拼接字符串的时候可以通过alloc属性判断是否会超出长度 减少修改字符串所带来的内存重新分配次数。...因为sds会预留内存空间(alloc>len),如果修改后的字符串长度小于alloc,则不需要重新分配内存 链表 在redis 源码中链表的定义可以通过adlist.h查看: /* Node, List...其中 header 和 tail 是结构体zskiplistNode的指针,这个结构体便是跳表的节点,它有如下属性: ele:成员对象; score:分值,用来排序; backward:后退指针,用于从表尾向表头遍历...level:数组,节点的层,包含forward(前进指针,用于表头向表尾遍历),span(跨度,用于记录两个节点之间的距离) 跳表的层可以包含多个元素,每个元素都包含指向一个节点的指针用于快速访问其他节点
*; 在函数中改变一个外部变量,需要变量的地址; 若是数据,需要指向数据的指针存储数据的地址; 若是指针,需要指向指针的指针存用户指针的地址; 数组与指针 p[i]等价于*(p+i),&p[i]等价于...,数据可以变化,可以在不修改地址的情况下管理数据,指针数组指向的数据不可变化,但地址可以变化,在不修改数据的情况下查看数据; 三维数组与指针,A[i][j][k]的三种表达形式:*(A[i][j]+k)...,功能是为已经分配的内存重新分配空间并复制内容,会自动将内存初始化为 0; realloc 原型:voidrealloc(void ptr,unsigned int size),ptr:已分配的内存地址...,size:重新分配的字节数 内存分区 C/C++中,内存分为:堆、栈、自由存储区、全局/静态存储区、常量存储区; 堆:由 new 分配的内存块,一般对应一个 delete,若没用释放,则程序结束后操作系统自动回收...、制表符、换行则表示结束; Unicode 字符问题 char 字符串可显示汉字,但字符不可以,字符连在一起用%c%c 可以输出一个汉字; 结构体 结构体引用方式:结构体数组名[下标].成员名; 结构体指针变量引用成员形式
array指针指向底层数组的地址,len代表的就是数组长度。...string可以为空,但是不能为nil,并且string的值是不能改变的。为什么string类型没有cap字段string的不可变性,也就不能直接向底层数组追加元素,所以不需要Cap。...= nil && len(s) <= len(buf) {*buf = tmpBuf{}b = buf[:len(s)]} else { //预定义数组长度不够,重新分配内存b = rawbyteslice...预先定义了一个长度为32的数组若字符串的长度不超过这个长度32的数组,copy函数实现string到[]byte的拷贝若字符串的长度超过了这个长度32的数组,重新分配一块内存了,再进行copy[]byte...,我们知道如果字符串长度超过32的话,会重新分配一块新内存,进行内存拷贝。
预空间分配:如果对一个SDS进行修改,分为一下两种情况: SDS长度(len的值)小于1MB,那么程序将分配和len属性同样大小的未使用空间,这时free和len属性值相同。...举个例子,SDS的len将变成15字节,则程序也会分配15字节的未使用空间,SDS的buf数组的实际长度变成15+15+1=31字节(额外一个字节用户保存空字符)。...惰性释放空间:当执行sdstrim(截取字符串)之后,SDS不会立马释放多出来的空间,如果下次再进行拼接字符串操作,且拼接的没有刚才释放的空间大,则那些未使用的空间就会排上用场。...通过惰性释放空间避免了特定情况下操作字符串的内存重新分配操作。...杜绝缓冲区溢出:使用C字符串的操作时,如果字符串长度增加(如strcat操作)而忘记重新分配内存,很容易造成缓冲区的溢出;而SDS由于记录了长度,相应的操作在可能造成缓冲区溢出时会自动重新分配内存,杜绝了缓冲区溢出
预空间分配:如果对一个SDS进行修改,分为以下两种情况: SDS长度(len的值)小于1MB,那么程序将分配和len属性同样大小的未使用空间,这时free和len属性值相同。...举个例子,SDS的len将变成15字节,则程序也会分配15字节的未使用空间,SDS的buf数组的实际长度变成15+15+1=31字节(额外一个字节用户保存空字符)。...惰性释放空间:当执行sdstrim(截取字符串)之后,SDS不会立马释放多出来的空间,如果下次再进行拼接字符串操作,且拼接的没有刚才释放的空间大,则那些未使用的空间就会派上用场。...通过惰性释放空间避免了特定情况下操作字符串的内存重新分配操作。...杜绝缓冲区溢出:使用C字符串的操作时,如果字符串长度增加(如strcat操作)而忘记重新分配内存,很容易造成缓冲区的溢出;而SDS由于记录了长度,相应的操作在可能造成缓冲区溢出时会自动重新分配内存,杜绝了缓冲区溢出
SDS 定义: struct sdshdr{ //记录buf数组中已使用字节的数量 //等于 SDS 保存字符串的长度 int len; //记录 buf 数组中未使用字节的数量...buf 数组中未使用的字节数量 上面的定义相对于 C 语言对于字符串的定义,多出了 len 属性以及 free 属性。...③、减少修改字符串的内存重新分配次数 C语言由于不记录字符串的长度,所以如果要修改字符串,必须要重新分配内存(先释放再申请),因为如果没有重新分配,字符串长度增大时会造成内存缓冲区溢出,字符串长度减小时会造成内存泄露...2、惰性空间释放:对字符串进行缩短操作时,程序不立即使用内存重新分配来回收缩短后多余的字节,而是使用 free 属性将这些字节的数量记录下来,等待后续使用。...2、将底层数组现有的所有元素都转成与新元素相同类型的元素,并将转换后的元素放到正确的位置,放置过程中,维持整个元素顺序都是有序的。 3、将新元素添加到整数集合中(保证有序)。
SDS 定义: struct sdshdr{ //记录buf数组中已使用字节的数量 //等于 SDS 保存字符串的长度 int len; //记录 buf 数组中未使用字节的数量 int free``;...[] 数组用来保存字符串的每个元素 3、free j记录了 buf 数组中未使用的字节数量 上面的定义相对于 C 语言对于字符串的定义,多出了 len 属性以及 free 属性。...③、减少修改字符串的内存重新分配次数 C语言由于不记录字符串的长度,所以如果要修改字符串,必须要重新分配内存(先释放再申请),因为如果没有重新分配,字符串长度增大时会造成内存缓冲区溢出,字符串长度减小时会造成内存泄露...2、惰性空间释放:对字符串进行缩短操作时,程序不立即使用内存重新分配来回收缩短后多余的字节,而是使用 free 属性将这些字节的数量记录下来,等待后续使用。...2、将底层数组现有的所有元素都转成与新元素相同类型的元素,并将转换后的元素放到正确的位置,放置过程中,维持整个元素顺序都是有序的。 3、将新元素添加到整数集合中(保证有序)。 升级能极大地节省内存。
但是这些容器在一下方面都有不同的性能折中 向容器中添加或者删除元素的代价 非顺序访问容器中元素的代价 标准库中顺序容器主要有: vector:可变大小的数组。...、引用、指针都会失效 容器操作可能使迭代器失效 在向容器中添加元素后: 如果容器是vector或者string,且存储空间被重新分配,则指向容器的迭代器、指针都会失效。...如果存储空间未重新分配,指向插入位置之前的迭代器、指针、引用仍然有效,但是指向插入位置之后元素的迭代器、指针和引用将会失效 对于deque,插入到首尾位置之外的任何位置都会导致迭代器、指针和引用失效。...如果往容器中添加一个新元素时,发现容器空间已经不够了,就需要重新分配空间。并将已有元素逐一拷贝到新的内存空间中,然后添加新元素。...为了避免这种代价,标准库实现者采用了可以减少容器空间重新分配次数的策略。
int free; // 记录buf数组中未使用字节的数量 char buf[]; // 字节数组,用于保存字符串。...注意这里并没有指明数组的长度,这是一个柔性数组(flexible array member) }; 优势分析 预分配:SDS会为buf分配额外的未使用空间(通过free字段记录),这意味着当你向一个...SDS字符串追加内容时,如果未使用空间足够,Redis就不需要重新分配内存。...例如,当你使用sdscat函数向一个SDS字符串追加内容时,该函数会首先检查未使用空间是否足够,如果不够,则会重新分配更大的内存空间,并将原有数据复制到新位置,然后再追加新内容。...例如,当向一个使用压缩列表实现的列表中添加一个新元素时,如果添加后的列表仍然满足压缩列表的使用条件(即元素数量和大小都没有超过预设的阈值),那么Redis会直接在压缩列表的末尾添加新元素。
embstr编码是通过调用一次内存分配函数来分配一块连续的空间,而raw需要调用两次。 ? int 编码字符串和 embstr 编码字符串在一定条件下会转化为 raw 编码字符串。...embstr:<= 39 字节; int:8个字节的长整型; raw:> 39 个字节的字符串 1.3.2 空间分配 如果对一个SDS进行修改,分为一下两种情况: 长度小于1MB:程序将分配和 len...举个例子,SDS的len将变成15字节,则程序也会分配15字节的未使用空间,SDS的buf数组的实际长度变成15+15+1=31字节(额外一个字节用户保存空字符) 长度大于等于1MB:程序会分配 1MB...插入数据时,都需要用 realloc 重新申请内存,申请内存可能是重新分配整个新 ziplist 的内存,也可能是在 ziplist 尾部申请空间。...1 层的前驱指针,用于从底层表尾向表头方向遍历;
我们通过控制相应对象有多少成员来限制对哈希表大小的控制。例如,哈希表以 1024 字节开头,但如果我们向对象添加超过 512 个元素,哈希表将重新分配到 8192 字节。...在这种状态下,每个对象都有一个 1024 字节的哈希表。但是,仅向其中一个对象添加一个元素将导致其哈希表增长到 8192 字节。...将 513 元素添加到前 1000 个对象,导致 1000 次分配 8192 字节哈希表。 使用长度为 300 和 170 个元素的数组触发 Array.sort。...立即(在第一个数组元素的 toString() 方法中)将第 513 个元素添加到第二个 1000 个对象。这使我们非常确定,到目前为止,排序缓冲区与哈希表之一相邻。...在同一个 toString() 方法中,还会向数组添加更多元素,这将导致它超出范围。 图 5 显示了围绕排序缓冲区地址(红线)的堆可视化。
另外,Redis 除了处理 C 字符串之外,还需要处理单纯的字节数组,以及服务器协议等内容, 所以为了方便起见,Redis 的字符串表示还应该是二进制安全的:程序不应对字符串里面保存 的数据做任何假设,...数据可以是以 \0 结尾的 C 字符串,也可以是单纯的字节数组,或者其他 格式的数据。...则不会重新分配 buf 内存,因为追加的长度小于 18 ,追加后结构体的数据为: struct sdshdr { len = 25; free = 11; // 空白的地方为预分配空间,共 18...struct dictht { // 哈希表节点指针数组(俗称桶,bucket) dictEntry **table; // 指针数组的大小 unsigned long size; // 指针数组的长度掩码...之间的比率: 比率在 1:1 时,哈希表的性能最好; 如果节点数量比哈希表的大小要大很多的话,那么哈希表就会退化成多个链表,哈希表 本身的性能优势就不再存在; rehash 条件 dictAdd 在每次向字典添加新键值对之前
,避免环的产生 3、字典:key-value 存储方式,通过hash值计算,判断key的存储,当容量过大,会通过rehash重新分配字典大小 5、跳跃表 ---- 5.1 概述 跳跃表...2、前进指针:用于指向表尾方向的前进指针 3、跨度:用于记录两个节点之间的距离 4、后退指针:用于从表尾向表头方向访问节点 5、分值和成员:跳跃表中的所有节点都按分值从小到大排序...,并为新元素分配空间 2、将底层数组现有的所有元素都转换成新的编码格式,重新分配空间 3、将新元素加入到底层数组中 比如,我们现在有如下的整数集合: ? ...第二步,将原有数据他们的数据类型转换为与新数据相同的类型:(重新分配空间后的数据) ? 第三部,将新数据添加到数组中: ?...,在有需要时,程序会根据新添加的元素类型改变这个数组的类型 升级操作为整数集合带来了操作上的灵活性,并且尽可能地节约了内存 整数集合只支持升级操作,不支持降级操作 7、压缩列表 ----
3.4 缓冲区重新分配 很多用户对象拥有与它们相关联的条目数组或其他形式的缓冲区。在添加或删除元素时,条目数组通常被调整大小以节省内存。...万一要求延时更新的数量超过预分配项的数量限制,win32k 用更合适的大小(4 个追加的项)重新分配数组。...,被通过在 SMWP 数组处理期间拒绝缓冲区的重新分配来应对。...DeferWindowPos 函数中观测到,函数在那里检查“正被处理的”标志位并只允许不会导致缓冲区重新分配的项被添加进数组。 4. 可利用性 在这一节中,我们评估由用户模式回调引发的漏洞的可利用性。...因此隔离这样的分配可以用来阻止攻击者为简单地重新分配已释放对象的内存而使用可伸缩的原型(例如字符串)。
领取专属 10元无门槛券
手把手带您无忧上云