FreeBSD のメモリレポートと ZFS ARC キャッシュの理解

FreeBSD のメモリレポートと ZFS ARC キャッシュの理解

FreeBSD におけるメモリレポートの不一致

FreeBSD のメモリレポートは、各ツールが「使用中」対「利用可能」メモリを定義するヒューリスティックが異なるため、システム監視ツール間で一貫性がないように見えることがあります。これは主に、OS が仮想メモリ (VM) システムを管理する方法と、パフォーマンス最適化のために RAM をディスクキャッシュとして利用する方法に起因します。

FreeBSD では、メモリは複数のページキューに分類されます:

  • Active: ユーザーランドプロセスが現在使用しているページ。
  • Inactive: しばらくアクセスされていないページ。再利用可能で、システムがメモリを必要とすると解放できる。
  • Laundry: スワップへ書き込まれる予定のページ。
  • Wired: カーネルまたはページアウトできないロックされたプロセスが使用するメモリ。このカテゴリには ZFS Adaptive Replacement Cache (ARC) も含まれる。
  • Free: 完全に未使用のメモリ。

Inactive ページや Wired メモリの一部(ディスクキャッシュなど)はカーネルによって再利用可能なため、ツールはそれらを「使用中」または「空き」とカウントするかを判断しなければなりません。

メモリ使用量における ZFS ARC の役割

ほとんどの最新 FreeBSD インストールでデフォルトのファイルシステムである ZFS は、Adaptive Replacement Cache (ARC) を使用して最近使用されたデータを RAM に保存します。標準のカーネルキャッシュとは異なり、ARC は従来の VM システムをバイパスし、"wired" メモリカテゴリ内に格納されます。

ARC はシステムがアプリケーション用により多くのメモリを必要としたときに自動的に縮小するよう設計されているため、実質的に再利用可能です。しかし、監視ツールが単に "active" と "wired" の合計を算出するだけだと、ARC キャッシュによりシステムが実際に必要とする以上の RAM を使用しているように見えてしまいます。

ARC の使用状況を正確に把握するには、管理者は sysctl を使って特定のカーネルパラメータを問い合わせることができます:

  • kstat.zfs.misc.arcstats.size: 現在のキャッシュサイズ。
  • kstat.zfs.misc.arcstats.c_min: 最小設定キャッシュサイズ。
  • kstat.zfs.misc.arcstats.c_max: 最大設定キャッシュサイズ。

ツールのヒューリスティック分析: btop、fastfetch、htop

ツールごとにメモリ使用量の算出式が異なるため、同一マシンでも矛盾したレポートが出ます。

btop

歴史的に btop は単純化されたヒューリスティック used memory = active + wired を使用していました。このアプローチは ARC の再利用可能性を無視し、Inactive ページも考慮しないため、FreeBSD ではしばしば不正確です。

fastfetch

fastfetch はより包括的な空きメモリ定義 free memory = free + inactive + cache を採用しています。その結果、used memory = total - free memory となり、利用可能リソースを楽観的に示すことが多いです。

htop

htop は通常、メモリカテゴリを個別に表示しますが、使用中メモリは used memory = wired + active + laundry と計算します。

btop のメモリレポートにおける重大バグ

btop のソースコード (src/freebsd/btop_collect.cpp) を調査したところ、FreeBSD ユーザーに影響を与える 2 つの重要な問題が見つかりました。

32 ビット整数オーバーフロー

btop はメモリページ数を u_int(符号なし 32 ビット整数)で保持していました。ページ数にページサイズを掛けてバイト数を算出する際、4 GiB(4,294,967,296 バイト)を超える値はラップアラウンドします。たとえば、使用メモリが 4.42 GiB のシステムが、整数オーバーフローのために 422 MiB しか使用していないと報告されることがあります。

レガシーキャッシュレポート

btopvm.stats.vm.v_cache_count からキャッシュデータを取得しようとしましたが、この sysctl パラメータは FreeBSD 12.0 以降「互換性のためのダミー」となっており常に 0 を返します。実際のキャッシュキューは FreeBSD 6.3.0 以降存在しません。

正しいメモリ追跡の実装

これらの不一致を解消するには、メモリ監視ツールが ZFS ARC と FreeBSD バッファキャッシュ (vfs.bufspace) を明示的に考慮する必要があります。

修正された使用メモリ計算ロジックは次の通りです:

  1. 総キャッシュの算出: vfs.bufspace と ARC の可変部分(現在サイズから最小サイズを引いたもの)を合計する。
  2. 生の使用量の算出: activewired メモリを合計する。
  3. 実際の使用量の算出: 計算したキャッシュを生の使用量から差し引く: usedBytes = (cachedBytes < rawUsed) ? rawUsed - cachedBytes : 0

これらの改善は btopfastfetch(ロジックを Linux や NetBSD を含むすべての ZFS 対応システムへ拡張)および htop に対するプルリクエストとして提出され、FreeBSD エコシステム全体で一貫した正確なメモリレポートが提供されるようになりました。

Sources