読者です 読者をやめる 読者になる 読者になる

必要最小ワーキングセット

あるプロセスの物理メモリ最大使用量を測定するというお話.『Cozy Ozy』より.

GetProcessMemoryInfoというAPIはどうかと思い、このようなコードを書いてみた。

最大の問題は,消費メモリ量をどう定義するか,ということかもしれません.
例えば 16*1024*1024 個の整数配列をソートすることを考えてみましょう.この作業,一見 64 MB 近い物理メモリが必要な気がしますが,実際にはデータを 64 MB のファイルに書き出して,それをちまちま読み書きしながらソートすればもっと少ないメモリで完走できそうです.
Windows 環境に限定して考えると,これは別にファイル I/O API を使う必要すらありません.64 MB のファイルをメモリ空間にマップして,必要な箇所だけ物理メモリを割り当てていけば,元のソートアルゴリズムをあまり変更せずに済みそうです.
さらに言えば,VirtualAlloc でメモリを確保するということはページファイルの一部をメモリマップすることに他なりませんから,自分でファイルを作る必要もありません.VirtualAlloc でメモリを確保する一方で,ソートアルゴリズムのあちこちに SetProcessWorkingSetSize API を仕込んでワーキングセットの縮小を行えば,あからさまに怪しいデータファイルとメモリマップ API をも排除することができます.
結局,VirtualAlloc と SetProcessWorkingSetSize だけで,「ファイルにデータを書き出して,それをちまちま読み書きしながらソートする」ことを実現することができます.
さらにさらに,SetProcessWorkingSetSize は別プロセスに対してもワーキングセットの縮小を指定することができますので,ソートを行うプロセスから切り出してしまうことができます.別プロセスからこっそりワーキングセットの縮小を指示するような共犯者を作ってしまえば,元のソースコードだけを見て「必要最小物理メモリ」を判断するのはほとんど不可能,というか行為そのものの意味が消失しかねないでしょう.
というわけで試してみましたが(ただし別プロセスから SetProcessWorkingSetSize を呼ぶというのは面倒なのでパス),ファイル I/O を一切使うことなく,16*1024*1024 個の整数配列を 1 MB ちょっとの PeakWorkingSetSize でソートできました.まあ実際には物理メモリは余りまくっているので,ページファイルに書き出されることなくスタンバイリストとワーキングセットを行ったり来たりしているだけでしょう.それでも原理上は 1 MB ちょっとの物理メモリしか余っていない環境でも動いてくれるんじゃないでしょうかね.
へう゛ぉいコードですが,一応このあたりに置いておきます.
http://www.dwahan.net/nyaruru/hatena/QSMem.zip



となると「 (タスクマネージャの) 仮想メモリ サイズ」を監視しよう,ということになりそうですが,アレはアレでページファイルじゃなくて通常のファイルをメモリマップした場合には増えないので,自前で 400 MB ぐらいのファイルを作ってメモリマップすれば,こんどは「省仮想メモリサイズ プログラミング」なんてのが可能です.id:NyaRuRu:20051022#p7 の Process Explorer に表示されている「Private Bytes」がタスクマネージャの「仮想メモリ サイズ」に相当します.