面试题答案
一键面试设计思路
- 空间预分配:在进行追加操作前,预估追加后字符串的长度。如果当前SDS空间不足,根据预估长度一次性分配足够的空间,避免多次分配内存。
- 惰性空间释放:对于删除操作,不立即释放空间,而是将多余空间记录下来,供后续追加操作使用。
代码示例(以C语言为例,Redis原生使用C实现SDS)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义SDS结构体
struct sdshdr {
int len;
int free;
char buf[];
};
// 创建一个新的SDS
struct sdshdr* sdsnew(const char *init) {
size_t initlen = (init == NULL)? 0 : strlen(init);
struct sdshdr *sh = (struct sdshdr*)malloc(sizeof(struct sdshdr)+initlen+1);
if (!sh) return NULL;
sh->len = initlen;
sh->free = 0;
if (initlen) {
memcpy(sh->buf, init, initlen);
}
sh->buf[initlen] = '\0';
return sh;
}
// 追加字符串到SDS
struct sdshdr* sdscat(struct sdshdr *s, const char *t) {
size_t len = strlen(t);
size_t avail = s->free;
if (avail < len) {
// 空间不足,重新分配
size_t newlen = s->len + len + len; // 预分配更多空间
struct sdshdr *newsh = (struct sdshdr*)realloc(s, sizeof(struct sdshdr)+newlen+1);
if (!newsh) return NULL;
s = newsh;
s->free = newlen - s->len;
}
memcpy(s->buf + s->len, t, len);
s->len += len;
s->free -= len;
s->buf[s->len] = '\0';
return s;
}
// 查询SDS中的字符串
char* sdsquery(struct sdshdr *s) {
return s->buf;
}
int main() {
struct sdshdr *s = sdsnew("Hello");
s = sdscat(s, ", World!");
printf("%s\n", sdsquery(s));
free(s);
return 0;
}
在上述代码中:
sdsnew
函数创建一个新的SDS,初始分配空间并复制初始字符串。sdscat
函数实现追加操作,在空间不足时根据追加字符串长度进行预分配。sdsquery
函数用于查询SDS中的字符串。
在基于Redis的应用中,可类似地利用SDS特性,通过合理的内存分配和管理,优化频繁字符串操作的性能。例如,在Redis客户端库中,可以在执行追加命令前,预估追加内容长度,提前分配空间;对于删除操作,标记多余空间,待后续追加使用。