> Go 1.24 起,`map` 的底层实现从传统的 `hmap` + `bmap` 哈希表,彻底切换到了 Swiss Table(瑞士表) ![Gemini_Generated_Image_jhqwi7jhqwi7jhqw](D:\zhangyuxin\code\lab\note\assets\golang-map[swiss table].png) ### Group内存布局图 你可以直接复制以下文本块到你的 Markdown 笔记中(使用 text 包裹): codeText ``` +-------------------------------------------------------------------------------+ | 单 Group 内存布局 | +--------------------------+----------------------------+-----------------------+ | 1. Metadata 控制字节区 | 2. 连续 Key 存储区 | 3. 连续 Value 存储区 | +--------------------------+----------------------------+-----------------------+ | [M0][M1][M2]...[M7] | [K0][K1][K2]...[K7] | [V0][V1][V2]...[V7] | +--------------------------+----------------------------+-----------------------+ | <- 固定 8 个字节 -> | <- 长度取决于 Key 类型 -> | <- 长度取决于 Val -> | | <- 一次性载入寄存器对比 -> | | ``` **为什么这样设计?(设计优势):** 1. 2. **避免内存对齐填充(Padding)**:如果采用 [Meta][Key][Value] 交叉排列,由于不同类型的 Key/Value 字节大小不同,为了对齐,Go 必须在它们之间插入大量空白填充字节,浪费空间。分块连续存储消除了组内的对齐损耗。 3. **对 CPU 缓存友好**:8 字节的 Metadata 紧密相连,一次 Cache Line 填充就能把整组的控制信息全部读入,极大地提高了缓存命中率。 ------ ### 读取流程 以下为您整理的完整、正确的读取逻辑,您可以直接复制使用: #### 1.哈希计算与分段 (Hash Splitting) - 将 Key 传入哈希函数,计算出一个 **64 位的哈希值**。 - 该哈希值被拆分为两部分:**H1(高 57 位)**:用于定位哈希表中的初始 Group 索引。**H2(低 7 位)**:作为特征值(指纹),存储在 Group 的 Metadata 中,用于快速匹配。 #### 2.定位初始 Group (Locate Group) - 计算初始 Group 索引:group_index = H1 & (Group数量 - 1)。 > 可以理解与$2^B$进行取模运算,但是**位与运算**效率更高且等价。 #### 3.组内快速匹配 (Group-level SWAR Match) - **一次性加载**:将目标 Group 的 8 字节 Metadata 一次性载入一个 64 位寄存器中。 - **并行对比(SWAR 技术)**:利用位运算,将 7 位的 H2 同时与这 8 个 Metadata 字节进行并行对比,输出一个 8 位的位掩码(Bitmask)。位掩码中为 1 的位,代表该位置的 H2 与目标 H2 匹配成功。这一步极快,完全避免了循环遍历。 #### 4.冲突解决与探测循环 (Verification & Probing Loop) 根据位掩码的匹配结果,执行以下逻辑: 1. 依次根据匹配成功的索引,去 **Key 存储区** 找到对应的真实 Key。 2. 进行完整的 Key 等值对比(如 if key == targetKey):**若匹配成功**:直接去 **Value 存储区** 对应偏移量取出 Value 并返回。**若匹配失败**:说明发生了 **H2 哈希冲突**(即不同的 Key 产生了相同的 H2),继续对比下一个匹配的槽位。 3. 如果当前 Group 中所有匹配了 H2 的槽位都对比完了,仍未找到匹配的 Key,则**跳转至【情况 B】**。 此时需要检查当前 Group 的 Metadata 状态,决定是继续向后寻找还是停止: - **若当前 Group 中存在“空位”(Empty,0xFF)**: 说明探测链在此处断开,该 Key 在 Map 中**一定不存在**,直接返回 nil 或零值。 - **若当前 Group 中无空位,但存在“墓碑”(Tombstone,0x80)或已满**: 虽然当前 Group 没找到,但可能因为历史删除操作(留下了墓碑)或哈希冲突,导致数据被存到了后续的 Group。不能停止!使用**二次探测算法(Quadratic Probing)**计算下一个 Group 的索引,跳转回 **【3.组内快速匹配】** 继续循环寻找。