Generated by Answer me with HTML 0.5.7 · 2026-10-23 11:51 · ★ Star on GitHub
hy-memory 为什么涨得这么快
一个写死 10000 条的 embedding 缓存,单条 41 KB
根因是一行写死的缓存
- hy_memory/core/embed_service.py 有个 EmbedService._cache,类型是字典存 Python list。
- cache_size 默认 10000,且 _build_config 不传这个字段,改不了。
- 单条 1024 维 list[float] 实测占 41 KB,1 万条就是 400 MB。
- 这不是泄漏,是缓存填满后停住。
证据链
| 环节 | 数据 | 来源 |
|---|---|---|
| 代码位置 | core/embed_service.py 第 87 行 | 源码 |
| 缓存上限 | 10000 条,写死 | 第 62 行 dataclass 默认值 |
| 存储类型 | Dict[str, List[float]] | 第 87 行 |
| 单条实测占用 | 41 KB | 本机 2000 条实测 |
| 外推 1 万条 | 400 MB | 41 KB × 10000 |
| 冷启基线 | 90 MB | 重启后实测 |
| 满额预计 RSS | 约 490 MB | 90 加 400 |
| 历史峰值 | 507 MB | 看门狗触发记录 |
对照实验
同样 2000 条 1024 维数据,用 np.float32 存只要 7.5 KB 一条,是 list 的五分之一。存 float32 时 1 万条仅 73 MB。
涨得快但不泄漏
数据
| 10:36 | 90MB |
|---|---|
| 11:16 | 164MB |
| 11:35 | 398MB |
| 11:47 | 402MB |
| 11:50 | 393MB |
- 冷启到 398 MB 只用了 59 分钟,那是缓存填充期。
- 之后三个采样点 397.6、397.6、393.0,已经平台化。
- 每条唯一文本都新增一条缓存,这轮对话查询和写入密集,所以填得快。
- 同一查询命中缓存就不再新增,所以速度会自己降下来。
- 缓存到 10000 条就停止增长,既不加也不淘汰。
- 每次重启缓存清零,重新填一遍,这就是重启后从 90 MB 又回到 400 MB 的循环。
换后端的真实效果
| 方案 | 缓存层 400 MB | 向量层 | 净效果 |
|---|---|---|---|
| 现状 chroma | 不动 | 约 50 MB 壳 | 基准 |
| 切 no faiss | 不动 | 更差 | 不推荐 |
| 切 qdrant | 不动 | 要多开进程 | 更差 |
- hy_memory 自带 faiss 后端,596 行,配置级可切,不用改代码。
- 但它的 _data 里把每条 embedding 再用 list 存一份,41 KB 乘 1911 条约 78 MB。
- 索引用 IndexFlatIP,暴力精确检索,不做任何压缩。
- 也就是比 chroma 多一份 Python 副本,切过去更占内存。
- 增长发生在缓存层,换任何向量后端都碰不到它。
真正有效的两个修法
| 方案 | 改动量 | 上限 | 代价 |
|---|---|---|---|
| A 缓存条数降到 2000 | 一行 | 82 MB | 命中率降,embedding 调用变多 |
| B 改存 np.float32 | 5 处读写 | 73 MB | 命中率不变 |
- 方案 B 单条从 41 KB 降到 7.5 KB,1 万条也只占 73 MB。
- 两者都改 site-packages 里的文件,hy-memory 升级会覆盖,需要重打。
- 生效要重启 hy-memory,看门狗本来也会重启,不影响对话。
- 现在的 450 MB 阈值刚好够它停在 400 MB 平台,可能再也不触发重启。 AM_EOF