深入解析yyjson项目的核心数据结构设计
yyjson The fastest JSON library in C 项目地址: https://gitcode.com/gh_mirrors/yy/yyjson
yyjson是一个高性能的JSON库,其卓越的性能很大程度上源于精心设计的数据结构。本文将深入剖析yyjson中的核心数据结构设计,帮助开发者更好地理解其内部工作原理。
一、数据结构概览
yyjson采用了两套平行的数据结构体系:
| 类型 | 不可变版本 | 可变版本 | |------------|------------------|---------------------| | 文档结构 | yyjson_doc | yyjson_mut_doc | | 值结构 | yyjson_val | yyjson_mut_val |
关键设计理念:
- 不可变数据结构:在解析JSON文档时创建,解析后内容不可修改
- 可变数据结构:在构建JSON文档时使用,支持动态修改
- 两套结构可相互转换,满足不同场景需求
这种设计既保证了解析时的极致性能,又提供了构建时的灵活性。
二、不可变值结构(yyjson_val)
不可变值是JSON解析后的基础存储单元,其C结构定义如下:
struct yyjson_val {
uint64_t tag;
union {
uint64_t u64;
int64_t i64;
double f64;
const char *str;
void *ptr;
size_t ofs;
} uni;
}
精妙的内存布局设计:
-
tag字段:64位复合字段
- 低8位存储数据类型(如字符串、数字、布尔值等)
- 高56位存储数据大小(字符串长度、数组元素数等)
-
uni联合体:根据类型存储实际值
- 数值类型直接存储
- 字符串存储指针
- 容器类型存储偏移量
设计优势:
- 充分利用现代64位CPU特性(通常物理地址限制在52位内)
- 紧凑的内存布局减少缓存未命中
- 类型与大小信息合并存储,减少内存访问
三、不可变文档结构(yyjson_doc)
不可变文档采用连续内存布局设计,极大提升了访问效率。
字符串存储区
- 连续内存块:所有字符串存储在单一连续内存区域
- 原地转义:解析时直接处理转义字符
- 零拷贝:字符串保留原始指针,无需额外复制
值存储区
- 值连续存储:所有值对象存储在另一连续内存区域
- 高效遍历:容器类型自带大小信息,支持快速子元素访问
- 紧凑布局:减少内存碎片,提高缓存命中率
四、可变值结构(yyjson_mut_val)
可变值在不可变值基础上增加了修改能力:
struct yyjson_mut_val {
// 同yyjson_val的字段
uint64_t tag;
union {...} uni;
// 新增链表指针
yyjson_mut_val *next;
}
链表设计特点:
- 保留不可变值的紧凑存储优势
- 通过next指针实现链表结构
- 支持动态增删改操作
五、可变文档结构(yyjson_mut_doc)
可变文档采用创新的循环链表设计:
- 循环链表:对象/数组的子元素构成循环链表
- 尾指针优化:父节点持有链表尾部指针
- 高效操作:
- 追加操作:O(1)时间复杂度
- 前置操作:O(1)时间复杂度
- 删除操作:O(1)时间复杂度
六、内存管理模型
yyjson采用文档级内存管理策略:
-
文档生命周期:
- 负责管理所有值和字符串内存
- 必须显式调用
yyjson_doc_free()
释放
-
值生命周期:
- 与所属文档绑定
- 不能单独释放
-
设计优势:
- 减少内存分配次数
- 批量释放提高效率
- 避免内存泄漏
七、性能优化启示
通过分析yyjson的数据结构设计,我们可以总结以下高性能设计原则:
- 连续内存布局:减少内存碎片,提高缓存利用率
- 复合字段设计:充分利用CPU字长,紧凑存储元数据
- 差异化设计:不可变与可变结构分离,各司其职
- 时间复杂度优化:特殊数据结构实现O(1)操作
- 零拷贝理念:最大限度减少内存复制
这些设计理念不仅适用于JSON解析,对于其他高性能库的开发也具有借鉴意义。
理解yyjson的数据结构设计,有助于开发者更高效地使用该库,并在需要性能调优时做出正确决策。
yyjson The fastest JSON library in C 项目地址: https://gitcode.com/gh_mirrors/yy/yyjson
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考