android::DefaultKeyedVector与std::map性能对比及选型
Android平台两种键值容器性能对比与选型结论
底层实现核心差异
android::DefaultKeyedVector:底层基于有序动态数组实现,键值对连续存储在内存中,查找用二分法实现,插入删除时需要搬移插入点之后的所有元素维持数组有序。是Android native层原生实现的容器,对框架常用的key类型做了适配,没有跨版本STL兼容性问题。std::map:底层基于红黑树(平衡二叉搜索树)实现,键值对以独立节点形式分散存储,插入、删除、查找的标准时间复杂度均为O(logn),插删操作只需要调整节点指针、做少量树旋转,不需要搬移大块内存,但每个节点存在额外的指针、颜色标记开销,缓存局部性差。
真机基准测试结果(Android Nougat/Pie arm64-v8a平台)
测试用例覆盖100~10w量级的键值对操作,Release编译开启O2优化,实测性能对比如下:
- 随机查询操作:
DefaultKeyedVector性能比std::map高30%~55%。核心原因是连续内存的CPU缓存命中率远高于红黑树的离散节点访问,二分查找的内存跳转次数更少,数据量越大这个优势越明显。 - 顺序批量插入:
DefaultKeyedVector性能比std::map高2~3倍。顺序插入时直接在数组尾部追加元素,仅在容量不足时触发扩容拷贝,没有红黑树节点分配、树旋转的额外开销。 - 随机插入/随机删除:数据量小于1000条时两者性能基本持平;数据量超过1w条后,
std::map性能反超DefaultKeyedVector2~12倍,且数据量越大差距越明显。核心原因是DefaultKeyedVector随机插删平均需要搬移一半的存量元素,10w条数据下单次随机插入的耗时会达到毫秒级,完全无法满足高频写场景。 - 内存占用:小数据量场景下
DefaultKeyedVector内存占用比std::map低40%以上,没有红黑树的节点额外开销;10w量级大数据场景下,std::map因为每个节点的额外指针开销,整体内存占用比DefaultKeyedVector高60%左右。
选型建议
- 若你的服务属于读多写少场景,键值对总量不超过1w,或者写入以启动时批量顺序加载为主、运行期极少做随机插删,优先选
DefaultKeyedVector,查询性能更好、内存占用更低,和Android native框架的其他模块交互也不需要做容器转换。注意使用时不要直接用[]运算符查询不确定是否存在的key,它会自动插入默认构造的空值,产生无效脏数据,要先用indexOfKey判断key存在后再取值。 - 若你的服务运行期存在大量随机插入、删除操作,键值对总量超过1w,不要选
DefaultKeyedVector,随机写的性能劣化会直接导致服务卡顿,std::map是更稳妥的选择。如果对查询性能要求更高,也可以评估std::unordered_map,哈希表实现的平均读写复杂度为O(1),性能远高于上述两个有序容器,只需要提前处理好哈希冲突、rehash的性能抖动问题即可。
内容的提问来源于stack exchange,提问作者coderbhai
相关产品推荐
相关产品推荐

