使用对象指针作为std::unordered_map的值为何是性能改进?
为什么第二种实现是低延迟场景下的改进?
先明确两种实现的核心差异:
第一种实现:std::unordered_map<InstrumentId, Instrument>
unordered_map 的底层哈希表中,每个桶的链表节点直接存储完整的 Instrument 对象。这意味着:
- 所有
Instrument对象分散在内存的不同位置(哈希冲突导致的链表节点、哈希表扩容后的重新哈希,都会让对象内存地址完全不连续) - 每次访问
Instrument对象,都是直接对大体积对象进行随机内存访问,缓存几乎无法命中,因为缓存预加载的连续内存块根本覆盖不到这些分散的对象
第二种实现:std::vector<Instrument> + std::unordered_map<InstrumentId, Instrument*>
这种方案把数据存储和索引分离:
vector负责存储所有Instrument对象,利用其连续内存布局的特性,所有对象在内存中是紧密排列的unordered_map只存储键InstrumentId和指向vector中对象的指针
核心改进点:
- 缓存命中率大幅提升:
虽然 unordered_map 中的指针依然是随机分布的,但指针本身体积极小(64位系统下仅8字节),哈希表的节点体积大幅缩小,缓存行可以容纳更多哈希节点,哈希查找的缓存命中率更高。
而当你通过指针访问Instrument对象时,这些对象在vector的连续内存中,缓存可以预加载相邻的对象——如果业务中存在批量访问(比如遍历多个关联工具、处理一组行情数据),这种连续内存带来的缓存友好性会极大降低内存访问延迟。 - 内存分配更高效:
vector采用预分配+扩容的方式,一次性申请大块内存,避免了第一种方案中每次插入都要为Instrument对象做小内存分配的开销(低延迟系统中,频繁小内存分配不仅慢,还会导致内存碎片化)。 - 哈希表的内存开销降低:
存储指针比存储完整Instrument对象占用的内存少得多,哈希表整体内存占用更小,进一步提升缓存效率。
回应你的疑问:
你说的“仍然存在链表结构、随机访问”是事实,但两种场景下的随机访问完全不同:
- 第一种是随机访问大体积的业务对象,缓存完全无法发挥作用,每次访问都要从内存甚至磁盘加载
- 第二种是随机访问极小体积的指针,然后通过指针访问连续内存中的业务对象,指针的随机访问开销可以忽略,而对象的访问是缓存友好的
这就是为什么第二种方案在低延迟系统中是显著的改进。
内容的提问来源于stack exchange,提问作者blanNL
相关产品推荐
相关产品推荐

