bitset内存压缩达1/8因用1位存1布尔值,64个布尔值仅占1个uint64(8字节),理论压缩比8倍,实际7~7.8倍;如存100万标志位,[]bool占约1MB,bitset仅需~125KB。
为什么 bitset 能把内存压到 1/8?
因为 []bool 每个元素占 1 字节(8 位),而 bitset 把 64 个布尔值塞进一个 uint64,平均每位只占 1/64 字节。理论压缩比是 8 倍;实际中因对齐和元数据开销,通常稳定在 7~7.8 倍。比如存 100 万个标志位:[]bool 占约 1mb,bitset 只要 ~125kb。
用 github.com/gh_mirrors/bit/bitset 还是 math/big.Int?
看场景:
- 确定位数上限、追求极致性能 → 用
github.com/gh_mirrors/bit/bitset:底层是[]uint64,无 GC 压力,Set/Test是纯位运算,纳秒级 - 位索引可能极大(如 > 1e9)、动态不可预估 → 用
math/big.Int:自动扩容,SetBit(&x, i, 1)安全,但每次操作有小开销,且二进制表示不紧凑(高位零也占空间) - 需要交集/并集/差集等集合运算 →
bitset库提供And/Or/Sub方法,直接按 word 并行处理;big.Int得自己实现或转成字符串再解析,不现实
SetRange 和逐位 Set 的性能差多少?
差一个数量级。比如设置连续 1000 位:
- 用循环调
bs.Set(i):触发 1000 次索引计算 + 1000 次位或,还可能多次触发extendSet - 用
bs.SetRange(0, 999):内部按uint64对齐切分,起始/结尾部分生成掩码,中间整块直接赋值^uint64(0),一次写 64 位 - 实测在现代 CPU 上,后者快 5–12 倍,且缓存友好
容易被忽略的边界坑点
bitset.New(n) 创建的是「最多支持 n 位」的结构,但索引从 0 开始,所以合法范围是 0 到 n-1。常见错误:
-
bs := bitset.New(100); bs.Set(100)→ panic: "You are exceeding the capacity" -
bs.SetRange(10, 20)表示设置第 10 到第 20 位(含),共 11 位,不是长度为 10 的区间 - 清空位集不能用
bs = bitset.New(bs.Cap()),会丢掉原有容量信息;应调bs.ClearAll()或重用实例 - 并发读写必须加锁 ——
bitset本身不是线程安全的,哪怕只是Test和Set交叉执行也可能读到撕裂值
[]bool;该换 bitset 的地方,晚换一天,GC 就多扫一次 MB 级切片。











