claude-memプラグインのChromaDBが420GBに肥大化していた原因と対処方法
はじめに
Claude Codeのプラグインとして提供されているclaude-memは、会話の文脈をベクターデータベース(ChromaDB)に記録し、セッション間で知識を保持する仕組みを持っています。
このclaude-memを使い続けていたところ、macOSのストレージ設定画面で「書類」カテゴリが545GBを占めていることに気づきました。大きなファイルは一通り削除したはずなのに空き容量が回復しなかったため、何らかのキャッシュやデータが肥大化しているのではないかと疑い、調査を始めました。
この記事では、よくあるキャッシュ削除では解決しなかった545GBの内訳を追跡し、最終的にclaude-memの旧ChromaDBインデックスにたどり着くまでの過程を記録しています。
環境
- macOS Sequoia(Darwin 25.3.0)
- Claude Code(Claude Opus 4.6)
- claude-mem v10.3.1(thedotmackのマーケットプレイス版)
- ChromaDB(claude-memの内部で使用)
macOSのストレージ表示で異変を検知する
システム設定のストレージ画面を開くと、「書類」が545.27GBと表示されていました。アプリケーション(57GB)やシステムデータ(146GB)と比較して明らかに大きく、何がディスクを圧迫しているのかが直感的にはわかりませんでした。
まず一般的な原因を疑って掃除する
開発マシンでディスクが圧迫されている場合、真っ先に疑うのはDockerイメージ、ビルドキャッシュ、パッケージマネージャのキャッシュです。心当たりのあるものを順に削除しました。
Dockerの不要データを削除する
Dockerは使わなくなったイメージやビルドキャッシュが蓄積しやすいため、まずここから手を付けました。
docker system prune -a
コンテナの停止済みデータや未使用イメージが削除されましたが、ストレージ表示にはほとんど変化がありませんでした。
Flutterのビルドキャッシュを削除する
Flutter開発でもビルドキャッシュがGBクラスになることがあります。
flutter clean
各プロジェクトのbuildディレクトリやDartのビルド成果物が削除されましたが、これも目立った効果はありませんでした。
XcodeのDerivedDataとシミュレータキャッシュを削除する
Xcodeは特にDerivedDataが肥大化しやすく、開発者のディスク圧迫の定番です。
rm -rf ~/Library/Developer/Xcode/DerivedData/*
シミュレータのキャッシュも確認しましたが、数GB程度の削減にとどまりました。
npmとHomebrewのキャッシュを削除する
npm cache clean --force
brew cleanup --prune=all
ゴミ箱を空にする
Finderのゴミ箱にファイルが残っていると、ディスクの空き容量には反映されません。ゴミ箱を空にして確認しましたが、やはりストレージ表示は545GBのままでした。
ここまでの操作で、一般的に大きくなりがちなキャッシュ類はほぼ削除済みです。にもかかわらず「書類」が500GB以上を占めているということは、通常のキャッシュではない何かが存在しているはずです。
コマンドラインで本格的に調査する
macOSの「書類」カテゴリはユーザーのホームディレクトリ配下のデータを広く含みます。GUIのストレージ表示では内訳がわからないため、duコマンドで実際のディスク使用量を調べることにしました。
ホームディレクトリの通常ディレクトリを確認する
まず、ホームディレクトリ直下のディレクトリサイズを確認しました。
du -sh ~/*/ 2>/dev/null | sort -rh | head -20
87G /Users/your-username/Library/
17G /Users/your-username/devs/
7.1G /Users/your-username/systemi_repos/
4.5G /Users/your-username/Documents/
1.9G /Users/your-username/fvm/
通常のディレクトリを合計しても120GB程度で、545GBには遠く及びません。残りは隠しディレクトリにあるはずです。
隠しディレクトリのサイズを確認する
ドットで始まる隠しディレクトリのサイズを確認しました。
du -sh ~/.[!.]* 2>/dev/null | sort -rh | head -10
420G /Users/your-username/.claude-mem
8.6G /Users/your-username/.cache
4.7G /Users/your-username/.local
2.3G /Users/your-username/.konan
2.2G /Users/your-username/.vscode
2.0G /Users/your-username/.m2
1.3G /Users/your-username/.rustup
1.3G /Users/your-username/.npm
1.2G /Users/your-username/.kiro
1.2G /Users/your-username/.dartServer
.claude-memディレクトリが420GBを占めていました。545GBのうち77%がこの1つのディレクトリに集中しています。
DockerでもFlutterでもXcodeでもなく、Claude Codeのプラグインが原因でした。ここに到達するまでにかなりの時間を費やしたのは、隠しディレクトリを後回しにしていたからです。ディスク調査では、まずduで全体像を確認してからキャッシュ削除に進むほうが効率的です。
claude-memの内部構造を掘り下げる
.claude-memの中身を確認しました。
du -sh ~/.claude-mem/*/ 2>/dev/null | sort -rh
420G /Users/your-username/.claude-mem/chroma/
197M /Users/your-username/.claude-mem/vector-db/
31M /Users/your-username/.claude-mem/logs/
420GBのほぼ全量がchroma/ディレクトリに集中していました。
肥大化したファイルを特定する
ChromaDBのHNSWインデックスファイルを個別に確認しました。
ls -lah ~/.claude-mem/chroma/4fdd99c1-7313-4cf8-b74e-8e980c72b39e/
-rw-r--r-- 48M data_level0.bin
-rw-r--r-- 100B header.bin
-rw-r--r-- 590K index_metadata.pickle
-rw-r--r-- 118K length.bin
-rw-r--r-- 1.1T link_lists.bin
link_lists.binの論理サイズが1.1TBと表示されました。ただし実際のディスク使用量はスパースファイルのため420GBです。
スパースファイルとは
スパースファイルは、ファイルの中身のほとんどがゼロ(空)であるときに、そのゼロ部分を実際にはディスクに書き込まず、メタデータだけで管理する仕組みです。
たとえば論理サイズが1TBのファイルでも、実際にデータが書き込まれている領域が400GBであれば、ディスク上の使用量は400GBになります。ls -lhで表示されるのは論理サイズ(1TB)ですが、du -hで表示されるのは実際のディスク使用量(400GB)です。
statコマンドの%z(論理サイズ)と%b(割り当て済みブロック数)を比較することで、スパースファイルかどうかを判定できます。両者に大きな差があればスパースファイルです。
今回のケースでは、HNSWインデックスのデータ追加・削除によってファイル内の離れた位置にデータが散在し、間のゼロ領域が膨大に生まれた結果、論理サイズと実使用量の乖離が生じていました。
stat -f "Apparent size: %z bytes, Disk blocks: %b" ~/.claude-mem/chroma/4fdd99c1-*/link_lists.bin
Apparent size: 1216337185268 bytes, Disk blocks: 880574216
ディスクブロック数 × 512バイト = 約420GBであることが確認できました。
正常なDBとの比較で異常さを確認する
claude-mem内にはもう1つvector-db/というChromaDBディレクトリが存在していました。同じファイル構成を比較すると、異常さが明確にわかります。
ls -lah ~/.claude-mem/vector-db/ac9ceb3e-f3cf-44cc-8647-2e8b41469a46/
-rw-r--r-- 51M data_level0.bin
-rw-r--r-- 100B header.bin
-rw-r--r-- 1.6M index_metadata.pickle
-rw-r--r-- 125K length.bin
-rw-r--r-- 276K link_lists.bin
data_level0.bin(ベクターデータ本体)はどちらも約50MBで同等ですが、link_lists.bin(HNSWインデックス)は420GB対276KBと、約160万倍の差がありました。
ChromaDBのレコード数を確認する
格納されているデータ量を確認しました。
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;"
4416
sqlite3 ~/.claude-mem/chroma/chroma.sqlite3 "SELECT COUNT(*) FROM embeddings;"
31704
観測データ4,416件、エンベディング31,704件に対して420GBのインデックスは明らかに異常です。
原因の特定
バージョンアップによるDB移行が未完了だった
claude-memのワーカースクリプト(worker-service.cjs)を調査したところ、v10.3へのアップグレード時に旧chroma/ディレクトリを自動削除するマイグレーション機能が存在していました。
この機能はchroma-cleaned-v10.3というマーカーファイルの有無で判定されます。マーカーが存在しなければchroma/を削除し、新たにvector-db/を使用する設計です。
cat ~/.claude-mem/chroma-cleaned-v10.3
marker does not exist
マーカーファイルが存在しなかったため、マイグレーションが正常に完了しなかったことがわかりました。結果として、旧chroma/(420GB)は孤立したまま放置され、現行システムはvector-db/(197MB)を正常に使用していました。
HNSWインデックスが肥大化した理由
HNSWはベクター近似最近傍探索のためのグラフ構造インデックスです。データの追加と削除を繰り返すと、link_lists.binにスパースな領域が蓄積してファイルが肥大化します。旧バージョンのclaude-memでは、このインデックスの再構築やコンパクション処理が行われていなかったため、使用を続けるうちに420GBまで膨れ上がったと考えられます。
対処する
旧DBが使用中でないことを確認する
削除の前に、ファイルがどのプロセスにも使われていないことを確認しました。
lsof /Users/your-username/.claude-mem/chroma/chroma.sqlite3
# → 出力なし(使用中のプロセスなし)
ps aux | grep chroma | grep -v grep
# → 出力なし(chromaプロセスなし)
旧chromaディレクトリを削除する
使用されていないことが確認できたので、旧ディレクトリを削除しました。
rm -rf ~/.claude-mem/chroma/
マイグレーションマーカーを作成する
claude-memの再起動時にマイグレーションが再実行されないよう、マーカーファイルを作成しました。
date -u +"%Y-%m-%dT%H:%M:%S.000Z" > ~/.claude-mem/chroma-cleaned-v10.3
現行DBをVACUUMで最適化する
ついでに現行のSQLiteデータベースもVACUUMで最適化しました。VACUUMを実行するにはclaude-memワーカーを一度停止する必要があります。
# ワーカーを停止する
curl -s -X POST http://127.0.0.1:37777/api/admin/shutdown
# claude-mem.dbのVACUUM
sqlite3 ~/.claude-mem/claude-mem.db "VACUUM;"
# vector-db内のChromaDB SQLiteのVACUUM
sqlite3 ~/.claude-mem/vector-db/chroma.sqlite3 "VACUUM;"
# WALファイルを削除する
rm -f ~/.claude-mem/claude-mem.db-shm ~/.claude-mem/claude-mem.db-wal
ワーカーを再起動する
bun ~/.claude/plugins/cache/thedotmack/claude-mem/10.3.1/scripts/worker-service.cjs --daemon
ヘルスチェックで正常起動を確認します。
curl -s http://127.0.0.1:37777/api/health
{"status":"ok","version":"10.3.1"}
結果
対処前後のサイズ変化をまとめます。
| 対象 | 対処前 | 対処後 |
|---|---|---|
~/.claude-mem/全体 |
420GB | 251MB |
claude-mem.db |
34MB | 27MB |
vector-db/chroma.sqlite3 |
135MB | 132MB |
| ディスク空き容量 | 211GB | 661GB |
約420GBのディスク領域を回復できました。
macOSのストレージ表示が更新されない場合
削除後にmacOSのシステム設定でストレージを確認しても、表示が即座に変わらない場合があります。macOSのストレージカテゴリ分類はSpotlightのインデックスに基づいているため、反映にはシステム設定の再起動、またはMac本体の再起動が必要なことがあります。
df -hコマンドで空き容量が増えていることを確認できれば、削除自体は正常に反映されています。
考察:ツールのアーキテクチャを確認する習慣について
今回の420GBの肥大化は、claude-memプラグインの内部でChromaDBのHNSWインデックスがコンパクションなしに際限なく成長した結果です。この問題にはいくつかの教訓があります。
プラグインが内部で何を動かしているのかを把握する
claude-memは「会話を記憶するプラグイン」として導入しましたが、その内部ではChromaDBというベクターデータベースが常駐プロセスとして動作し、ホームディレクトリの隠しフォルダにデータを書き込み続けています。
開発ツールやプラグインを導入する際、README上の機能説明だけで判断してインストールすることは珍しくありません。しかし、そのツールが内部でどのようなミドルウェアを起動し、どこにデータを永続化し、どのような成長特性を持つのかを事前に確認しておかないと、今回のように気づかないうちにディスクを圧迫されることがあります。
特にベクターデータベースやログ収集系のツールは、明示的に削除しない限りデータが増え続ける設計のものが多いため、導入時にデータの保存先と管理方針を確認しておくことが重要です。
DBのインデックス肥大化は実務でも頻繁に発生する
今回の現象は、プラグインという文脈を離れてみれば、RDBやNoSQLの運用でよくある「インデックスの肥大化」と本質的に同じ問題です。
PostgreSQLでは大量のUPDATE/DELETEの後にデッドタプルが蓄積し、VACUUM FULLやREINDEXを実行しないとテーブルとインデックスが肥大化します。MongoDBのWiredTigerストレージエンジンでも、コレクションの削除後にディスクが解放されず、compactコマンドの実行が必要になる場合があります。
ChromaDBのHNSWインデックスも同様で、ベクターの追加と削除を繰り返すとグラフ構造に空洞が生まれます。本番環境であればモニタリングで気づけますが、ローカルマシンのプラグインが裏で動かしているDBには監視の目が届きません。定期的にduでデータディレクトリのサイズを確認する程度の習慣があれば、今回のような事態を早期に発見できます。
マイグレーション失敗の静かな影響
今回のもう1つの問題は、v10.3へのアップグレード時に旧DBの削除マイグレーションが静かに失敗していたことです。マーカーファイルが書き込まれなかったにもかかわらず、新しいvector-db/は正常に動作していたため、旧chroma/が420GBのまま残っていることに気づく手段がありませんでした。
マイグレーションの失敗がエラーとして表面化しない設計は、ユーザー体験としては親切ですが、リソース管理の観点では問題を隠蔽してしまいます。特にディスク使用量のような累積的な影響は、失敗時にログやワーニングとして記録される仕組みがあると発見が早まります。
まとめ
claude-memプラグインを長期間使用していると、旧バージョンのChromaDBインデックスが数百GBに肥大化する場合があります。macOSのストレージ設定画面で「書類」が異常に大きい場合は、~/.claude-mem/chroma/ディレクトリの存在を確認してみてください。
v10.3以降のclaude-memではDBがvector-db/ディレクトリに移行されていますが、マイグレーションが正常に完了しなかった場合には旧データが残り続けます。lsofで使用状況を確認した上で、旧ディレクトリの削除とマーカーファイルの作成を行えば、安全にディスクを回復できます。
開発ツールを導入する際には、そのツールが内部で何を永続化しているかを把握しておくことが大切です。便利なプラグインほどバックグラウンドで多くのことを行っているため、ディスク使用量の定期的な確認を習慣にしておくと、今回のような問題の早期発見につながります。
Discussion