大きなファイルを一度だけ読み進める処理では、読み終わった部分よりも、これから使うデータへメモリーを回したいことがあります。Linuxで使えるposix_fadviseのDONTNEEDは、その意図をカーネルへ伝える方法です。ただし、指定したバイト数がそのまま解放量になるわけではありません。範囲の境界、ページの状態、処理結果を分けると、この機能を過大評価せずに使えます。
簡単にまとめると?
- POSIX_FADV_DONTNEEDは、近く使わないファイル範囲のキャッシュを解放するよう促すヒントです。指定量の解放完了を約束する命令ではありません。
- 範囲の端で一部分だけが含まれるページは、破棄の対象から外れます。バイト単位の指定とページ単位の扱いを区別します。
- 未書き出しの変更が残るページにも制約があります。戻り値0、候補ページ数、実際の解放量を同じ数字として扱わないことが大切です。
読み終えた範囲を、今後の利用予定として伝える
posix_fadviseは、ファイル記述子fdと、開始位置offset、長さsize、助言の種類adviceを受け取ります。DONTNEEDという種類を指定すると、その範囲を近い将来は使わないという予定を伝え、関連するキャッシュページの解放を試みます。公式マニュアルは、助言には強制力がないことも明示しています。[1、DESCRIPTION]
たとえば、ファイルを先頭から順に処理し、読み終えた区間へ戻らない集計を考えます。その区間を再利用する見込みが小さければ、そこに残るキャッシュより、別のデータを置く余地が役立つかもしれません。反対に、直後に同じ区間を読み直す処理なら、残っていたキャッシュが役立つ可能性があります。「読めたから不要」ではなく、これからのアクセス予定に合わせて判断する機能です。
ここで対象としているのはファイルデータのキャッシュです。ファイルの内容を削除する操作や、安全なデータ消去の手順として読むものではありません。また、以下の数値例は範囲の考え方を確かめる独自モデルであり、OSのキャッシュを実際に変更する実験ではありません。
9000バイトを指定しても、丸ごと含むのは1ページ
説明を簡単にするため、ページの大きさを4096バイトと仮定します。これは例の条件であり、あらゆる環境のページサイズを固定する説明ではありません。先頭から三つのページを、ページ0が0以上4096未満、ページ1が4096以上8192未満、ページ2が8192以上12288未満の範囲として並べます。
開始位置1000、長さ9000の範囲は、1000以上10000未満です。三つのページに重なりますが、ページ0の先頭1000バイトは範囲外、ページ2の末尾2288バイトも範囲外です。丸ごと含まれるのは中央のページ1だけで、その大きさは4096バイトになります。指定した9000バイトと、丸ごと含むページの合計4096バイトは一致しません。
この違いが重要になるのは、DONTNEEDでは一部分だけを破棄する要求が無視されるためです。[1、POSIX_FADV_DONTNEED] ページ0や2を丸ごと捨てれば、指定範囲の外にある部分まで巻き込みます。バイト範囲の途中から途中までを指定できることと、その端のページも丸ごと解放対象になることは別です。
独自モデルでは、各ページの開始が要求の開始以上であり、ページの終端が要求の終端以下であるものだけを数えています。同じ4096バイトの長さでも、4096から8192未満なら1ページ全体が入る一方、5000から9096未満では二つのページにまたがり、丸ごと入るページは0です。長さだけでは候補数を判断できません。

境界が合っていても、未書き出しの変更は残る
次に、0以上12288未満を指定する例を考えます。今度は三つのページ全体が入り、範囲だけを見れば候補は3です。しかし、ページ1に変更後まだ書き出されていないデータがあると仮定すれば、同じ結論にはできません。
マニュアルによると、実装がその範囲のdirty page、つまり書き出すべき変更を持つページの書き戻しを試みることはありますが、保証されません。未書き出しのdirty pageは解放されません。[1] この制約を独自モデルへ加えると、三つのうちページ1を除いたページ0と2の二つが、範囲と未書き出し状態の両条件を満たす候補になります。
この「候補2」は、2ページが実際に消えたという観測値ではありません。モデルはページの境界とdirty状態だけを入力にしており、実カーネルの状態や他の処理を再現していないためです。資料は書き戻しが必要な場合のfsyncやfdatasyncにも触れていますが、書き戻しを待つ処理を加えれば、元の処理の待ち時間やエラー処理も考える必要があります。本稿の例から一律に追加すべき操作とは決められません。
戻り値と解放量を、別の問いとして扱う
posix_fadviseは成功時に0、エラー時にはエラー番号を返します。[1、RETURN VALUE] 返す数字は解放したバイト数ではありません。0だったから9000バイト解放された、と読んだり、返された数を処理済みバイト数として足し合わせたりすることはできません。
確認したいことを三段階にすると整理しやすくなります。第一に、呼び出しがエラーになっていないか。第二に、範囲はどのページを丸ごと含み、未書き出しの変更という制約がないか。第三に、実際の対象環境でキャッシュや処理時間がどう変わったかです。本稿の計算が扱うのは第二段階の一部です。第一段階の成功を第三段階の成果に置き換えません。
また、端数をなくすために開始を前へ、終端を後ろへ広げれば、もともと指定していなかった領域まで含まれます。ページ境界へ合わせること自体を目的にせず、その追加領域も本当に近く使わないのかを確認する必要があります。読み終えた区間の管理と再利用予定を先に定め、それに合う範囲で助言する方が、単に大きな数字を指定するより判断の根拠を明確にできます。
出典
- Linux man-pages 6.19, posix_fadvise(2)。ページ日付2026年2月8日、HTML版2026年9月9日。DESCRIPTION、POSIX_FADV_DONTNEED、RETURN VALUE。2026年10月23日確認。4096バイトを仮定した範囲例と図は独自作成。実キャッシュの解放量、実機性能、ファイルシステムの挙動を測定したものではない。
