@@ -650,7 +650,7 @@ search:
6506501 . 是不是已经到了 load factor 的临界点,即元素个数 >= 桶个数 * 6.5,这时候说明大部分的桶可能都快满了,如果插入新元素,有大概率需要挂在 overflow 的桶上。
6516512 . overflow 的桶是不是太多了,当 bucket 总数 < 2 ^ 15 时,如果 overflow 的 bucket 总数 >= bucket 的总数,那么我们认为 overflow 的桶太多了。当 bucket 总数 >= 2 ^ 15 时,那我们直接和 2 ^ 15 比较,overflow 的 bucket >= 2 ^ 15 时,即认为溢出桶太多了。为啥会导致这种情况呢?是因为我们对 map 一边插入,一边删除,会导致其中很多桶出现空洞,这样使得 bucket 使用率不高,值存储得比较稀疏。在查找时效率会下降。
652652
653- 两种情况官方采用了不同的解决方法:
653+ 两种情况官方采用了不同的解决方法:
654654
655655* 针对 1,将 B + 1,进而 hmap 的 bucket 数组扩容一倍;
656656* 针对 2,通过移动 bucket 内容,使其倾向于紧密排列从而提高 bucket 利用率。
@@ -930,6 +930,128 @@ func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) {
930930}
931931```
932932
933+ 代码看着比较抽象,再补两个图:
934+
935+ * sameSizeGrow
936+
937+ ```
938+ ┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
939+ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
940+ └──────────┼──────────┴─────┬────┴──────────┴──────────┴──────────┴──────────┴──────────┘
941+ ┌────────────────┐ │ tophash: 10 │
942+ │ empty │ │ lowbits: 1001 │
943+ │ │◀─────┐ ├────────────────┤
944+ ├────────────────┤ │ │ empty │
945+ │ empty │ │ │ │
946+ │ │ │ ├────────────────┤
947+ ├────────────────┤ │ │ empty │
948+ │ empty │ │ │ │
949+ │ │ │ │ ├────────────────┤
950+ │ ├────────────────┤ │ │ tophash: 23 │
951+ │ │ empty │ │ │ lowbits: 0001 │
952+ │ │ │ │ ├────────────────┤
953+ │ ├────────────────┤ │ │ empty │
954+ ┌──────────┐ │ │ empty │ │ │ │
955+ │ before │ │ │ │ │ ├────────────────┤
956+ └──────────┘ │ ├────────────────┤ │ │ tophash: 100 │
957+ │ │ empty │ │ │ lowbits: 0001 │
958+ │ │ │ │ ├────────────────┤
959+ │ ├────────────────┤ │ │ empty │
960+ │ │ tophash: 15 │ │ │ │
961+ │ │ lowbits: 0001 │ │ ├────────────────┤
962+ │ ├────────────────┤ │ │ empty │
963+ │ │ empty │ │ │ │
964+ │ │ │ │ ├──────────┬─────┘
965+ │ └────────────────┘ └───────│ overflow │
966+ │ └──────────┘
967+ │
968+ │
969+ │
970+ │
971+ │ ┌────────────────┐
972+ │ │ tophash: 10 │
973+ │ │ lowbits: 1001 │
974+ │ ├────────────────┤
975+ │ │ tophash: 23 │
976+ │ │ lowbits: 0001 │
977+ │ ├────────────────┤
978+ │ │ tophash: 100 │
979+ │ │ lowbits: 0001 │
980+ │ ├────────────────┤
981+ │ │ tophash: 15 │
982+ │ │ lowbits: 0001 │
983+ │ ├────────────────┤
984+ ┌──────────┐ │ │ empty │
985+ │ after │ │ │ │
986+ └──────────┘ │ ├────────────────┤
987+ │ │ empty │
988+ │ │ │
989+ │ ├────────────────┤
990+ │ │ empty │
991+ │ │ │
992+ │ ├────────────────┤
993+ │ │ empty │
994+ │ │ │
995+ │ ┌──────────┼──────────┬─────┴────┬──────────┬──────────┬──────────┬──────────┬──────────┐
996+ │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
997+ │ ├──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┤
998+ │ │ │
999+ │ │ │
1000+ │ │ │
1001+ │ │ │
1002+ │ │ │
1003+ │ │ │
1004+ │ │ │
1005+ │ │◀───────────────────────────── X part ──────────────────────────────▶│
1006+ │ │ │
1007+ ▼ │ │
1008+ │ │
1009+ │ │
1010+ │ │
1011+ ```
1012+
1013+ sameSizeGrow 之后,数据排列更紧凑。
1014+
1015+ * biggerSizeGrow
1016+
1017+ ```
1018+ ┌──────────┐ ┌──────────┬───────────
1019+ │ 0 │ │ 0 │ ▲
1020+ ├──────────┼───────────────┬────────────────┐ ├──────────┤ │
1021+ │ 1 │ tophash: 10 │ tophash:23 │ ┌─────▶│ 1 │ │
1022+ ├──────────┤ lowbits: 1001 │ low bits: 0001 │──────┘ ├──────────┤ │
1023+ │ 2 ├───────────────┴────────────────┘ │ 2 │ │
1024+ ├──────────┤ │ ├──────────┤
1025+ │ 3 │ │ │ 3 │
1026+ ├──────────┤ │ ├──────────┤ X part
1027+ │ 4 │ │ │ 4 │
1028+ ├──────────┤ │ ├──────────┤
1029+ │ 5 │ │ │ 5 │ │
1030+ ├──────────┤ │ ├──────────┤ │
1031+ │ 6 │ │ │ 6 │ │
1032+ ├──────────┤ │ ├──────────┤ │
1033+ │ 7 │ │ │ 7 │ ▼
1034+ └──────────┘ │ ├──────────┼───────────
1035+ │ │ 0 │ ▲
1036+ │ ├──────────┤ │
1037+ └─────────────────────────────────────▶│ 1 │ │
1038+ ├──────────┤ │
1039+ │ 2 │ │
1040+ ├──────────┤
1041+ │ 3 │
1042+ ├──────────┤ Y part
1043+ │ 4 │
1044+ ├──────────┤
1045+ │ 5 │ │
1046+ ├──────────┤ │
1047+ │ 6 │ │
1048+ ├──────────┤ │
1049+ │ 7 │ ▼
1050+ └──────────┴───────────
1051+ ```
1052+
1053+ 桶数组增大后,原来同一个桶的数据可以被分别移动到上半区和下半区。
1054+
9331055## indirectkey 和 indirectvalue
9341056
9351057在上面的代码中我们见过无数次的 indirectkey 和 indirectvalue。indirectkey 和 indirectvalue 在 map 里实际存储的是指针,会造成 GC 扫描时,扫描更多的对象。至于是否是 indirect,依然是由编译器来决定的,依据是:
0 commit comments