用long[]实现超低内存布隆过滤器,规避对象开销,按位操作存64个状态/long;根据n和ε算出bit数m,对齐64得long数组长度;哈希用位运算加速,无装箱、无扩容、无计数器,clear()用arrays.fill高效清零。

用Java基本数据类型实现超低内存布隆过滤器,核心是绕开对象封装开销,全程使用long[]或byte[]做底层存储,配合位运算完成哈希映射与状态标记。关键不在“多快”,而在“多省”——避免每个bit都包装成Boolean对象,也不用BitSet(它内部有额外字段和方法表)。
用long数组代替BitSet,按位操作存状态
Java中long占64位,一个long可存64个布尔状态。若预计最大元素数为n,误判率ε≈0.01,则所需bit数m ≈ −n·lnε / ln2 ≈ 9.6n;再向上对齐到64的倍数,得到long数组长度size = (m + 63) >> 6。所有操作基于位运算:
- 设索引i(0 ≤ i idx = i >> 6,位偏移
bit = i & 63 - 置位:
bits[idx] |= (1L - 查位:
(bits[idx] & (1L
用int做哈希种子,生成多个独立哈希值
不依赖Objects.hash()或String.hashCode()(会创建临时对象),改用MurmurHash3的纯int版本或简化版DoubleHash:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 对任意key(如String),先算基础hash:
h = key.hashCode() * 0x1b873593(乘法扰动) - 生成k个哈希值(k=3~5):
hash[i] = (h + i * (h >>> 10)) & (m - 1),其中m是bit总数且为2的幂(便于&代替%) - 全程只用int运算,无对象分配,无装箱
避免扩容与动态结构,用静态容量+预估参数
布隆过滤器一旦初始化就不可扩容。因此设计时必须提前确定:预期插入元素数n、可接受误判率ε、哈希函数个数k(通常取(m/n)·ln2,四舍五入为整数)。计算出m后直接分配固定大小long[] bits,不预留扩展空间,不维护size/capacity字段。
- 构造函数只接收n和ε,内部完成m、k、bits数组一次性分配
- 不提供add/remove计数器,不记录已插入数量(除非业务强需,否则加int字段就是多占4字节)
- clear()只需
Arrays.fill(bits, 0L),比逐位清零快得多
字符串key处理:避免substring和new String
如果key常为字符串子串(如日志中提取的URL路径),直接用CharSequence接口+charAt()遍历,或传入char[]+offset+len,跳过创建新String对象:
- 哈希计算循环中,用
for (int i = start; i - 若key是UTF-8 byte[],直接按byte遍历,避免new String(byte[])触发解码和对象创建
- 所有输入参数尽量用原始数组或不可变视图,不包装
这套实现能让百万级元素的布隆过滤器内存占用压到100KB以内,比用BitSet小30%,比Guava BloomFilter小50%以上,且GC压力趋近于零。本质是把“数据结构”退回到“内存布局+位指令”的层面,用可控的CPU换不可控的堆内存。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










