FreeBSD が私の RAM を食い尽くした

2026/07/04 4:08

FreeBSD が私の RAM を食い尽くした

RSS: https://news.ycombinator.com/rss

要約

日本語翻訳:

上記に不足している要素と推測された飛躍が特定されているため、改善版を提供します:

サマリー(改善版)

FreeBSD で以前使われていた

btop
htop
といったシステム監視ツールは、廃止されたカーネル統計量に依存していたため、不正確なメモリ使用量の表示を行っていましたが、具体的には有効な ZFS ARC キャッシュを誤って除外したり、高メモリシステムでは 32 ビット整数の巻き戻りエラーが発生してしまい、5 GB 以上のメモリーが存在しながらも利用可能な RAM が低いと示すような誤った報告を引き起こしていました。この核心的な問題は、FreeBSD 12.0 以降のダミー
sysctl
値を使用していたこと(実際のページキャッシュカウントを報告しなくなったこと)と、ZFS ARC の存在下でアクティブ、非アクティブ、回収可能なメモリバッターを区別することができないことに由来していました。近代オペレーティングシステムは物理メモリーをページ(通常 4 KiB)に分割し、PQ_ACTIVE, PQ_INACTIVE, PQ_LAUNDRY, PQ_UNSWAPPABLE, PQ_NONE などのページキューを使用してカテゴリー化します。FreeBSD では、これらのカテゴリーは PQ_NONE 255, PQ_INACTIVE 0, PQ_ACTIVE 1, PQ_LAUNDRY 2, PQ_UNSWAPPABLE 3 などの定数によって定義されています。
top
はメモリーをアクティブ(ユーザーランドプロセス)、非アクティブ(最近アクセスされていない)、洗濯(スワップに書込むために用意されるもの)、ワイアド(カーネル使用中かつスワップ不能、ディスクキャッシュを含む)、フリー(未使用)として報告しますが、ZFS では独自の ARC(Adaptive Replacement Cache)を使用して最近使用されたデータをキャッシュし、カーネルの一般的なキャッシングメカニズムを回避します。ZFS ARC の統計量は
kstat.zfs.misc.arcstats.*
を介してアクセス可能であり、
gnumfmt
を使用して人間が読みやすい単位で表示できます。異なるツールは異なるヒューリスティックを使用しています:
fastfetch
はフリーメモリーをフリー + 非アクティブ + キャッシュとして計算し、使用メモリーを合計 - フリーとして計算します。当初
btop
は利用可能なメモリーを合計 - アクティブ - ワイアドとして計算し、ARC をワイアド報告から除外していました。一方
htop
はワイアド、アクティブ、洗濯をその使用メモリー計算に含めます。著者の最初の混乱は、コミュニティプロジェクトと共有した後の
fastfetch
の結果で、ユーザーが
fastfetch
btop
の間に不一致があると指摘したことから生じました。著者は OS internals の専門家ではありませんでしたが、数週間の独立した研究により、複数のオープンソースイニシアチブに重要な修正が導入されました。テストには、FreeBSD 13.5-RELEASE(ZFS)と 15.1-RELEASE(UFS)を実行する仮想マシンを作成すること、および FreeBSD 15.0-RELEASE を実行する ThinkPad X230 でのテストが含まれ、ファイルシステム全体でキャッシュバケットの問題が確認されました。著者は
dd
を使用してランダムファイルを生成し、それを読み返すことや、4 GB を割り当てて解放する C プログラムを使用して、
btop
などのツールにおけるキャッシュの成長と動態を観察しました。これらの問題に対処するために、著者は
btop
uint64_t
変数をスイッチすることで巻き戻りを防止し、かつ ZFS ARC ステータス (
arcsize - arcmin
) を使用して回収されたキャッシュを計算するように
vfs.bufspace
に加えて修正を行いました。
htop
に提出した PR では、ARC をワイアドから差し引きし、キャッシュ/バッタークラスを統合する変更を行い、初期の議論後に変更がマージされました。また、著者の入力に従って
fastfetch
は当初
v_cache_count
を使用していましたが、現在は ARC をサポートする他のプラットフォームとの並列で ZFS ARC 検出も含めるようになりました。これらの改善により、メモリー成分の正確な追跡が可能となり、管理者が誤って重要なディスクキャッシュをクリアしたり、総メモリー制限を誤解したりすることを防ぐことが可能になり、開発環境と生产環境の両方でパフォーマンスボトルネックの診断のための信頼性の高い基盤を提供します。今後の作業では、DragonFly BSD の調査を含め、これらの修正された基準に合わせてその報告方法を一致させることを検討しています。著者の貢献は、
btop
,
htop
,
fastfetch
という 3 つの重大なプロジェクトに対するパッチを生み出し、コミュニティ全体で FreeBSD メモリー使用量の監視精度を向上させることに寄与しました。この旅路は、若者の頃に「Operating Systems: Design and Implementation」を読みながら最初につくりかけられ、初期版のオリジナルのコピーを購入することから始まりました。

本文

FreeBSD サーバー移行と RAM 使用量報告の不一致:原因調査と修正記

先月、Ubuntu から FreeBSD へのサーバー移行記事について議論が進みました。特にメモリ(RAM)使用量の報告方法に対し、「fastfetch」と「btop」では大きく数字が異なるという指摘を受け、OS の内部構造を解明する調査を行いました。

本記事では、なぜ OS は「空きメモリ」を増やして見せかけるのかツール間の表示不一致の正体、そしてbtop に存在した重大なバグと修正プロセスについて詳述します。


1. RAM 使用量は定義が難しい

「Linux(または FreeBSD)が RAM を食った」と言うのは、システムが正常に機能している証拠です。CPU キャッシュのように、OS はディスクデータの読み込みを高速化するために RAM を活用しています。このキャッシュは揮発性を持ち、必要であればいつでも解放されます。

仮想メモリとページ管理

現代の OS は「仮想メモリ(VM)」を採用し、物理メモリのページ(4KiB)を以下のようなキューに分類・管理します。

キュー名定義
PQ_INACTIVE
(0)
一定時間アクセスされていないページ(解放候補)
PQ_ACTIVE
(1)
現在利用中のページ
PQ_LAUNDRY
(2)
スワップ対象の待機リスト
PQ_UNSWAPPABLE
(3)
スワップ不可能な領域(カーネル用など)

この管理ルールにより、OS は「未使用」であるはずの RAM を見つけると、必要な時にディスクへ一時保存(スワップ)できるように設定します。その後再度アクセスされると、再び RAM へ戻されます。

メモリのカテゴリと実質的な空き

top
コマンドなどで表示されるカテゴリには以下の意味があります。

カテゴリ説明
activeユーザープロセスで現在アクティブに利用されているページ
inactiveアクセスされておらず、インアクティブキューに移されたページ
laundryスワップ対象の待機リスト。空き不足時にここからデータを読み込む
wiredカーネル管理領域(
PQ_NONE
,
PQ_UNSWAPPABLE
)。ディスクキャッシュを含む
free未割り当てかつ未使用の純粋な空きメモリ

重要なポイント

  • **「inactive」も実質的な「free」**です。アクセス直前であれば即座に再利用可能です。
  • 「wired」の中にもディスクキャッシュが含まれるため、実質的に利用可能なメモリとして扱われます。
  • この仕組みにより、「実際に使われている量」と「空きメモリ」の境界は曖昧になります。

2. ディスクキャッシュ(ARC)について

FreeBSD のデフォルトファイルシステムである ZFS は、ARC(Adaptive Replacement Cache) という高度なキャッシュ機構を採用しています。直近にアクセスされたデータを RAM に保持することで読み込み性能を飛躍的に向上させます。

  • ARC はシステムが利用可能なメモリが増えるほど大きくなります。
  • カーネル自体も同様の機構を持ちますが、ZFS の ARC は独自に動作します。

ARC ステータスの確認方法

カーネルパラメータ

kstat.zfs.misc.arcstats.*
を確認可能です。

# 全てのパラメータを表示
sysctl kstat.zfs.misc.arcstats

# 特に重要な 3 つのパラメータを抽出表示
sysctl -n kstat.zfs.misc.arcstats.size          # 現在のキャッシュサイズ
sysctl -n kstat.zfs.misc.arcstats.c_min        # キャッシュ最小値
sysctl -n kstat.zfs.misc.arcstats.c_max        # キャッシュ最大値

出力例(

gnumfmt
で可読化):

$ sysctl -n kstat.zfs.misc.arcstats.size | gnumfmt --to=iec
3.1G

この数値は

top
コマンドでも詳細に確認できます。


3. なぜ fastfetch と btop は異なる表示をするのか?

各ツールがメモリ使用量を表示する際、「どの値を『使用済み』とみなすか」という判定基準(ヒューリスティック)が異なります。

ツールの計算ロジック比較

ツール計算式・論理結果の傾向
fastfetch
free = free + inactive + cache

used = total - free
キャッシュを含めるため、**「使用メモリ率が高い(例:82%)」**と表示。ZFS の ARC を「cache」として含める。
btop (旧)
available = total - active - wired

used = active + wired
キャッシュを見なさないため、「使用メモリ率が低く見える(例:7%)」
htop
used = wired + active + laundry
中間的な表示を行う。バー末尾に合計使用量を表示。

問題の一端:キャッシュ値が 0 であること

以前のスクリプトでは、fastfetch が表示した「cache」の値が常に 0 でした。これは btop と同じく、古くなったレガシーな sysctl パラメータを参照していたためです。


4. btop の FreeBSD 向けメモリ報告は重大な誤り

調査の結果、btop(および関連ツール)の FreeBSD 側の実装には致命的な欠陥が複数存在することが判明しました。

欠陥①:32 ビット整数による桁捨て(Overflow)

btop は FreeBSD の libc を介して

sysctl
でメモリ情報を取得しています。しかし、以下のコードで変数が
u_int
(符号なし 32 ビット整数)として宣言されています。

// [旧実装] 重大なバグ箇所
int mib[4];
u_int memActive, memWire, cachedMem, freeMem; // <--- u_int (最大約 4GB)
size_t len;

// ... sysctl 呼び出し省略 ...
memActive *= Shared::pageSize; // 超過すると桁捨てが発生
  • 32 ビット整数の限界: $2^{32} - 1 \approx 4.29$ GiB
  • 問題発生: RAM が 4GB を超えると、値が負数や異常な小さな数値(例:4.42 GiB → 422 MiB)として表示されてしまいます。
  • 結論: btop のメモリ計算ロジックは FreeBSD 環境では桁捨てにより致命的に間違っていることが確認されました。

欠陥②:キャッシュ情報の欠落 (
vm.stats.vm.v_cache_count
)

「Cached memory」の値が常に 0 である理由は、btop が参照している

v_cache_count
というパラメータ自体の問題にあります。

$ sysctl -n vm.stats.vm.v_cache_count
0
$ sysctl -d vm.stats.vm.v_cache_count
vm.stats.vm.v_cache_count: Dummy for compatibility
  • FreeBSD 12.0 以降、このパラメータは**「互換性用のダミー値(Dummy for compatibility)」**として機能しており、実際のキャッシュ情報を返しません。
  • btop は FreeBSD の最初の実装からこの非推奨なパラメータを参照し続けており、その理由さえ解明されていませんでした。

5. 修正策の開発と改善

調査に基づき、以下の 2 つの主要な修正を行いました。

修正①:データ型の昇格

メモリ量を保持する変数を

u_int
(32 ビット)から **
uint64_t
(64 ビット)**に変更し、4GB 超え時の桁捨て問題を解消しました。

修正②:キャッシュの正しく取得

ZFS の ARC キャッシュと一般的なファイルシステムキャッシュを適切に区別するロジックを実装しました。

HTop のコメントを参考に、「ZFS の場合、ARC は

buffers
にカウントされず
wired
に含まれる」ため、計算時に関連部分から引き下げる必要があります。

btop への適用された修正コード(一部):

// cached メモリの正しく取得処理(vfs.bufspace と ZFS ARC を組み合わせる)
uint64_t cachedBytes = 0; // uint64_t で宣言(旧: u_int から変更)

// vfs.bufspace (ファイルシステムキャッシュ)
if (sysctlnametomib("vfs.bufspace", mib, &len) == 0) {
    uint64_t bufSpace = 0;
    // sysctl 呼び出し省略 ...
    cachedBytes += bufSpace;
}

// ZFS ARC の取得(ZFS 環境のみ有効)
if (sysctlnametomib("kstat.zfs.misc.arcstats.size", mib, &len) == 0) {
    uint64_t arcSize = 0;
    // sysctl 呼び出し省略 ...
    // ARC の可変部分をキャッシュとして計上(最小サイズより大きい場合のみ差分を計算)
    cachedBytes += (arcSize > arcMin) ? (arcSize - arcMin) : 0;
}

// free メモリの取得
// sysctl(v_free_count)... 

// バイト単位の計算(uint64_t で桁捨て防止)
uint64_t activeBytes = (uint64_t)memActive * Shared::pageSize;
uint64_t wireBytes   = (uint64_t)memWire   * Shared::pageSize;
uint64_t freeBytes   = (uint64_t)freeMem   * Shared::pageSize;

// rawUsed: 実質的な使用メモリ(active + wired)
uint64_t rawUsed     = activeBytes + wireBytes;

// usedBytes: キャッシュを含めた総合「使用」量を正しく計算
// (キャッシュが over-report するのを防ぐために、rawUsed との比較で上限を設ける)
uint64_t usedBytes   = (cachedBytes < rawUsed) ? rawUsed - cachedBytes : 0;

mem.stats.at("used")     = usedBytes;
mem.stats.at("available") = Shared::totalMem - usedBytes;
mem.stats.at("cached")   = cachedBytes;
mem.stats.at("free")     = freeBytes;

テスト方法

キャッシュの挙動を確認するため、以下のようなテストを行いました。

  • /usr/src
    の数千ファイルを開く(効率が悪いため非推奨)。
  • dd
    を使用してランダムデータを大量に読み込む。
  • C プログラムで RAM を割り当て・解放するループを実行。

これにより、キャッシュが拡張される様子や、解放される際のメモリ変化をリアルタイムで確認できました。


6. fastfetch のケース

fastfetch も同様に

v_cache_count
からデータを取ろうとしており、提出した PR は却下されました(コメントなし)。しかし、その後以下の事実が判明しました。

  • 快挙: fastfetch は FreeBSD/NetBSD/Linux/ZFS などのマルチプラットフォーム対応を視野に入れ、ARC キャッシュを検出する機能を追加する形で改修が進んでいます。
  • 影響: 私の提案の一部がこの改修に取り入れられ、最終的に「正確なメモリ表示」が実現しました。

DragonFly BSD の注記 DragonFly BSD へのパッチも提出しましたが、そちらはまだ独自の表示方針(キャッシュを含む)を維持しているようです。今後さらに調査予定です。


おわりに

今回の調査を通じて以下の成果を得ることができました。

  1. 深い理解: FreeBSD の仮想メモリ内部構造とキャッシュ機構について詳細に学びました。
  2. コミュニティ貢献:
    • btop: 重大なバグの修正パッチを提出。
    • fastfetch/htop: 類似問題への対応を促し、結果的に改善につながりました。
    • Total: 主要なオープンソースプロジェクトに 3 つのパッチを提出する機会を得ました。
  3. 技術的回顧: 「OS を自作したい」という夢から始まるキャリアパスを再確認しました。「MINIX 本」(通称:OSDI)を読み込む中で感じた「50,000 行という規模」への衝撃は、現代の OS 開発においても色あせていません。

FreeBSD のメモリ管理は複雑ながら非常に優秀な設計です。今後も引き続き FreeBSD とオープンソースコミュニティに貢献してまいります。

同じ日のほかのニュース

一覧に戻る →

2026/07/04 7:40

巨大な木は問題なく水を上枝に送ることができます。

## Japanese Translation: エクセター大学とカーディフ大学が主導する新研究で、Science誌に発表された内容により、世界最高位の熱帯ティトロカルプ属(Dipterocarp)の樹木は、極めて高い位置での水分輸送課題を完全に補償できることが明らかになった。アジアの雨林を支配し、80 メートルを超える高さまで成長する巨大なティトロカルプ属の木々は、より低い木々に比べて旱魃に対する感受性を示さない。これは進化した水理学的適応によるものである。本研究は、2023 年~2024 年の激しいエルニーニョ現象を背景としてマレーシア・ボルネオで行われたものであり、7 メートルから 71 メートルの幅を持つ樹木が旱魃を通じて幹の成長速度を維持したことが見出された。これは、重力と導管の長さが高大型種における光合成および成長を制限するという長年の信念に挑戦するものである。より高いティトロカルプ属の木々は、地面付近で広く水分を運ぶ導管を持つことと、萎れる前により大きな水ストレスに耐えるように適応した葉を持つことによりこれを実現する。これらの適応は、80 メートル以上高く水を移動させるために必要な極めて低い圧力の下でも液体水の形態を維持することを可能にする。これらの結果は、特にアジアの地上バイオマス炭素の半分を貯蔵するティトロカルプ属森林において重要であり、水理学的システムが弱く高大型種では旱魃による急速な死に瀕するという以前の理論を矛盾させるものである。共同著者であるパウロ・ビッテンコート博士は、これらの希少樹木がマレーシア・ボルネオにおける生態学的中心性であることを強調しているが、研究者らは同様の特性を他の高大型樹種においても検討すべきであると指摘している。研究チームには、マレーシア、イギリス、チェコ共和国、ドイツ、スペイン、ブラジル、アメリカ合衆国の機関が含まれており、資金供与は自然環境研究評議会(NERC)からのものである。今後の研究では、ティトロカルプ属を超えた水理学的システムと旱魃耐性の調査を通じて、全球的な旱魃リスク評価および保全戦略を精査していく予定である。

2026/07/04 7:33

Leanstral 1.5:全データに対する証明の豊富さを実現

## Japanese Translation: Leanstral 1.5 は、60 億のアクティブパラメータと全パラメータとして 1190 億を持ち、競合製品のごく一部のコストで最先端のパフォーマンスを達成する無料の Apache-2.0 ライセンスモデルです。このモデルは miniF2F でサチュレーション(検証セットとテストセットで両方 100%)を達成し、PutnamBench の問題のうち 672 問中 587 問を解決します(25k トークンの予算では 44 問から、4M トークンの予算では 587 問へ向上)。FATE-H ベンチマークでは 87% の精度、FATE-X ベンチマークでは 34% の精度を達成しています。中学習(mid-training)、監督微調整、CISPO を用いた強化学習、特定の定理に対する安全性チェックを経て訓練された Leanstral 1.5 は、複数回のターンにわたる定理証明および生ファイルシステムでのコードエージェントにおけるエージェント型証明工学において卓越しています。ターゲットとなる定理のリストを用いて SafeVerify のフォーク版で検証され、このモデルは問題あたり約 $4 のコストがかかります(Seed-Prover の $300 以上や Aleph Prover の $54–68 に比べて著しく低く)、かつ大きなトークン予算と共によくスケーリングします。実際の運用では、オープンソースライブラリにおける微細なバグを検出し、57 リポジトリにわたって以前に知られていなかった 5 つのバグを発見しました。その例として、datrs/varinteger ライブラリにおいて `(value + 1)` が `Std.U64.MAX` 入力に対してオーバーフローした整数オーバーフローがありました。このモデルは Hugging Face で重みファイルおよび無料の API エンドポイント(leanstral-1-5)として利用可能です。ユーザーは Mistral Vibe(`uv tool install mistral-vibe`)で実行でき、Lean LSP MCP の設定をオプションで行うことで、その能力を活用し、高次の定理証明やバグ探索を行えるようにしながら、莫大なコストなしに動作させられます。

2026/07/04 6:49

AMD MI355X 上で GLM5.2 を実行し、コストは Blackwell よりも 2 倍以上低減してノードあたり 2626 トークン/秒を達成

## Japanese Translation: AMD の新しい Instinct MI355X アクセラレータは、NVIDIA の B シリーズ GPU に対して魅力的な代替手段を提供しており、B300 と比較して約 2.75 倍安い GPU 単価で同様のハードウェア仕様を備えています。また、B200 には 2 倍以上安いです。歴史的に CUDA エコシステムを通じて「day-0」の優位性を保持してきた NVIDIA ですが、AMD はこの格差を急速に縮めています。ROCm は当初、MI355X 上で GLM-5.2 のような frontier モデルに対してネイティブなサポートがなかったものの、ターゲットされた最適化によって B200 のノードあたり性能の約 80% を対価の少なさで実現しました。主要なブリークスルーとしては、AMD Quark を用いて損失のない MXFP4 量子化を実現し(公式の FP8 の制限を上回る)、出力劣化を伴わずに堅牢なネイティブ MXFP4 サポートのために sglang を選択し、モジュールプレフィックス不一致を修正したり、ROCm メタデータ カーネルガードを追加したりする特定のパッチを適用することで推測デコーディングの利点を解放(約 3 倍)した点があります。戦略的な構成チューニング(例えば TP4×DP2 への移行)や fp4 シェイプ用の MoE カーネルの最適化を通じて、カスタムカーネルを書かずにシングルノードデプロイメントで 2626 tok/s/node という SOTA の総通量を実現しました。この戦略は推論ワークロードに対して有効であり、AMD が NVIDIA の市場的地利を成功裏に侵食し、低コストで高計算能力を実現していることを示しています。また、マルチノードスケーリングに関する課題がまだ残るものの、よりバランスの取れた競争環境が育まれていることを意味します。

FreeBSD が私の RAM を食い尽くした | そっか~ニュース