SDS简单动态字符串:为什么Redis不用C字符串?

引言 在Redis中,我们使用SET和GET命令操作字符串,看起来和C语言的字符串没什么区别。但实际上,Redis并没有使用C语言传统的字符串表示(以空字符’\0’结尾的字符数组),而是自己实现了一种名为SDS(Simple Dynamic String,简单动态字符串)的抽象类型。 为什么要重新实现字符串?SDS有什么优势?今天我们深入源码,揭开SDS的神秘面纱。 一、C字符串的局限性 1.1 C字符串的表示 // C语言字符串 char str[] = "Redis"; // 内存布局 +---+---+---+---+---+---+ | R | e | d | i | s | \0| +---+---+---+---+---+---+ 0 1 2 3 4 5 1.2 存在的问题 问题1:获取字符串长度O(n) // 需要遍历整个字符串直到遇到'\0' size_t len = strlen(str); // O(n) 时间复杂度 // 对于频繁获取长度的场景(如Redis命令),性能损失严重 问题2:不支持二进制数据 // C字符串以'\0'作为结尾标志 char binary_data[] = {0x01, 0x02, 0x00, 0x03}; // ❌ 无法正确处理 // strlen会在遇到0x00时停止,认为字符串结束 // 导致无法存储图片、音频等二进制数据 问题3:容易缓冲区溢出 char dest[5] = "Hi"; char src[] = "Redis"; // ❌ 危险操作:没有检查dest空间是否足够 strcat(dest, src); // 缓冲区溢出!破坏相邻内存 问题4:内存重分配频繁 // 字符串拼接需要重新分配内存 char *str = malloc(6); strcpy(str, "Redis"); // 追加内容,需要重新分配 str = realloc(str, 12); // 每次都要重新分配,性能差 strcat(str, " Fast"); 问题5:不兼容部分C函数 // 很多C函数假设字符串以'\0'结尾 // 对于包含'\0'的二进制数据,这些函数无法正常工作 1.3 Redis的需求 Redis作为高性能数据库,对字符串的需求: ...

2025-01-21 · maneng

String类型深度解析:最简单也最强大

引言 在Redis的五大基础数据类型中,String是最基础、最常用的一种。据统计,在实际生产环境中,80%以上的Redis键都是String类型。 但String远不止"字符串"这么简单。它可以: 存储任意二进制数据(文本、数字、图片、序列化对象) 作为计数器(原子性递增/递减) 实现分布式锁 存储位图数据 今天我们从第一性原理出发,理解String的本质和强大之处。 一、String的本质 1.1 不只是字符串 在Redis中,String类型的"String"是一个容易误导人的名字。它实际上是: 二进制安全的字节数组(Binary Safe Byte Array) 这意味着: ✅ 可以存储文本:“hello world” ✅ 可以存储数字:123456 ✅ 可以存储JSON:{"name":"Redis"} ✅ 可以存储序列化对象:Java对象、Protobuf ✅ 可以存储二进制数据:图片、音频(理论上,但不推荐) 1.2 底层实现:SDS Redis使用自己实现的简单动态字符串(Simple Dynamic String, SDS),而不是C语言原生的字符串。 C字符串的问题: char* str = "hello"; // 问题1:获取长度需要遍历,O(n) int len = strlen(str); // 问题2:不是二进制安全,遇到\0就截断 char* binary = "hello\0world"; // 只能读到"hello" // 问题3:缓冲区溢出风险 strcat(str, " world"); // 可能溢出 SDS的优势: struct sdshdr { int len; // 已使用长度 int free; // 剩余可用空间 char buf[]; // 实际存储的字节数组 }; 优势: O(1)时间获取长度:直接读取len字段 二进制安全:不依赖\0判断结束 预分配空间:减少内存分配次数 惰性释放:空间不立即释放,可重用 1.3 内存占用 一个简单的String在Redis中的内存占用: ...

2025-01-21 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...