因为std::vector是特化容器,底层按位存储但operator[]返回代理对象,不支持取地址、原子操作、SIMD加速及data()访问,且内存不连续对齐;实操应改用std::vector手动位运算。

Bitmap 去重为什么不能直接用 std::vector<bool></bool>?
因为 std::vector<bool></bool> 是特化容器,底层按位存储但接口伪装成“元素可寻址”,导致 operator[] 返回代理对象而非引用,无法直接用于原子操作或内存映射场景;更关键的是它不保证连续内存布局,data() 可能返回 nullptr 或不可靠指针,对海量数据批量置位/扫描极不友好。
实操建议:
- 改用
std::vector<uint8_t></uint8_t>或std::vector<uint64_t></uint64_t>手动位运算,控制字节对齐与缓存行(64 字节)匹配 - 若数据范围固定且已知(如 0~10⁹),优先用
std::unique_ptr<uint64_t></uint64_t>配合new uint64_t[n],避免 vector 的容量扩张开销 - 注意:
uint64_t版本每 word 支持 64 个值,索引计算为idx / 64,位偏移为idx % 64,比uint8_t减少 8 倍随机访存次数
如何把 10 亿整数压缩进 125MB 以内?
理论下限是 10⁹ bit ≈ 119.2 MB,但实际必须考虑对齐、页边界和访问效率。直接申请 new uint64_t[15625000](10⁹ ÷ 64 = 15,625,000)刚好 125 MB(每个 uint64_t 占 8 字节),但 OS 分配可能向上对齐到 4KB 页,影响不大。
容易踩的坑:
立即学习“C++免费学习笔记(深入)”;
- 误用
sizeof(uint64_t)计算总字节数时没乘上数组长度 → 内存越界 - 未初始化内存:
new uint64_t[n]不初始化,必须memset(ptr, 0, n * sizeof(uint64_t))或用new uint64_t[n]()(带括号触发零初始化) - 跨平台注意:
uint64_t在 Windows MSVC 和 Linux GCC 下都可用,但若需 mmap 文件-backed bitmap,得用posix_memalign对齐到 4KB
set_bit() 和 test_bit() 怎么写才快?
核心是消除分支、利用 CPU 原子指令,并让编译器能向量化扫描。不要用条件判断是否越界——提前确保输入 idx 在合法范围内(由上层逻辑保障),否则加 assert 而非 if。
示例(无锁、内联、无分支):
inline void set_bit(uint64_t* bits, size_t idx) {
const size_t word_idx = idx >> 6; // 等价于 /64
const uint64_t mask = UINT64_C(1) << (idx & 63); // 等价于 %64
bits[word_idx] |= mask;
}
inline bool test_bit(const uint64_t* bits, size_t idx) {
const size_t word_idx = idx >> 6;
const uint64_t mask = UINT64_C(1) << (idx & 63);
return (bits[word_idx] & mask) != 0;
}
性能关键点:
- 用
idx >> 6和idx & 63替代除法取模,现代编译器虽会优化,但显式写出更可靠 -
UINT64_C(1)防止左移时 int 溢出(尤其在 32 位环境模拟下) - 若需线程安全,用
__atomic_or_fetch(&bits[word_idx], mask, __ATOMIC_RELAXED)(GCC/Clang),MSVC 用_InterlockedOr64
文件映射 Bitmap(mmap)时为何查得慢甚至崩溃?
常见现象:首次 mmap 后 test_bit() 延迟高、缺页异常多,或 munmap 后访问野指针报 Segmentation fault。
根本原因和对策:
- mmap 默认是 lazy allocation(首次访问才分配物理页),对 125MB bitmap 首次全量扫描会触发大量缺页中断 → 提前用
madvise(ptr, size, MADV_WILLNEED)或memset(ptr, 0, size)触发预读 - 未检查
mmap返回值是否为MAP_FAILED,尤其大内存映射在 32 位进程或内存碎片多时易失败 - 忘记
msync(ptr, size, MS_SYNC)就退出,导致去重结果未落盘;但频繁 sync 影响吞吐,建议批量写入后统一 sync - 路径权限错误:
open(..., O_RDWR)必须与 mmap 的PROT_READ | PROT_WRITE匹配,否则 segfault
真正难处理的是并发更新:多个进程 mmap 同一文件时,必须用文件锁(flock)或共享内存信号量协调,仅靠 bitmap 位操作无法保证一致性。


















