none
最大仮想メモリ使用量(プライベート分)の測定 RRS feed

  • 質問


  • 初めて投稿させていただきます。

    自前アプリの最大の仮想メモリ使用量(プライベート分)を、そのアプリ内で計
    測したいと考えております。

    Process Explorer(www.sysinternals.com)が Peak Private Bytes として表示
    している数値のことです。

    これを VC++ で実装するにはどのようにすればよいのでしょうか?何かヒントを
    いただけると助かります。

    Performance Data Helper Library(PDH) というものがありますが、この目的と
    関連する情報が検索では見つからなかったのと、PerfMon.msc(PDH を使ってい
    ると理解しています)でもこの値を見ることができないということは PDH では
    無理なのではという想像より、深く調べておりません。

    以下は、これまでに試したことです。

    DDK を導入し、NtQueryInformationProcess に VM_COUNTERS_EX 構造体のアドレ
    スを渡すことで、他の観点のメモリ使用量は計測することが出来ました。そこで、

    VM_COUNTERS_EX.PeakVirtualSize -
    (VM_COUNTERS_EX.VirtualSize - VM_COUNTERS_EX.PrivateUsage)

    により(括弧内はシェア分と考えています)、目的とする値を概算しようと考え
    ましたが、うまくいきませんでした。Process Explorer の示す値と近いことも
    ありましたが、負の値になることすらありました。プライベートの使用量がピー
    クになった時点でのシェア分が、NtQueryInformationProcess 呼び出し時点のシェ
    ア分とほぼ同じという保証などないので当然だと考えております。


    よろしくお願いいたします。

    開発環境:
    Windows XP Professional SP2、Visual Studio 2005 Professional、DDK 3790.1830
    アプリ動作環境:
    Windows 2000/XP Professional/XP Professional x64 Ed.

    2006年9月17日 16:14

回答

  •  

    > Process Explorer(www.sysinternals.com)が Peak Private Bytes として表示
    している数値のことです。

    psapi の GetProcessMemoryInfo で得られる情報では駄目なのでしょうか?

    Process Explorer と適当に書いたサンプルを見比べてみると、PROCESS_MEMORY_COUNTERS のPagefileUsage が Private Bytes に、PeakPagefileUsage が Peak Private Bytes に対応しているように見えます。

    Process Explorer 自身は psapi.dll を利用していないようですから、一致しない可能性もあります。そのあたりはきちんと確認してみて下さい。

     

    2006年9月19日 10:31

すべての返信

  •  

    > Process Explorer(www.sysinternals.com)が Peak Private Bytes として表示
    している数値のことです。

    psapi の GetProcessMemoryInfo で得られる情報では駄目なのでしょうか?

    Process Explorer と適当に書いたサンプルを見比べてみると、PROCESS_MEMORY_COUNTERS のPagefileUsage が Private Bytes に、PeakPagefileUsage が Peak Private Bytes に対応しているように見えます。

    Process Explorer 自身は psapi.dll を利用していないようですから、一致しない可能性もあります。そのあたりはきちんと確認してみて下さい。

     

    2006年9月19日 10:31
  • SAKAMOTO さん、コメントありがとうございました。
    お返事が遅くなり申し訳ありません。

     ご指摘の通り、PROCESS_MEMORY_COUNTERS の PeakPagefileUsage でいけそうです。また、同名のメンバが VM_COUNTERS にもありますが、この値も全く同じになることを確認しました。Process Explorer はVM_COUNTERS を使っているのかもしれません。

    PeakPagefileUsage というメンバがあるのは知っていたのですが、「ページアウトされたことのあるページだけを対象にしたものだろう」と考えてしまい、着目しておりませんでした。PeakVirtualSize や PrivateUsage に注目し過ぎていました。

    上の考え方は間違っていて、『ページファイル空間は、ページが初めて作成されるときに予約されますが、…』(インサイド Microsoft Windows 第 4 版 上 の 7.6.5 より引用)でいうところの予約がなされた段階で、PagefileUsage や PeakPagefileUsage にはカウントされる、というのが正しいと今は思っております。

    その裏づけために、char* p = new char[1000000]; などとした直後に、WorkingSetSize が増える場合でも、PeakPagefileUsage もほぼ同じだけ増えることを確かめました。余談になりますが、VC++ 2005 で作ったコンソールアプリで、Debug ビルドでは WorkingSetSize は増えましたが、Release ビルドでは増えませんでした(アクセスしてはじめて増えました)。

    ありがとうございました。

    2006年9月23日 18:47
  • 何度もすみません。

    「char* p = new char[1000000]; などとした直後に、WorkingSetSize が増える」のは、Debug ビルドでしたが、これは単に、Debug ビルドでは new の中で各バイトへの 0xcd の書き込みが起こっているからですね。Debug 版では new の最中にページフォールトが発生していました。

    私は、コミットしただけで RAM が使用される(はじめてアクセスされるときにページフォールトが発生しない)状況を発生させようとしていたわけですが、それはありえないのでしょうか?48*1024 バイトという小さな領域を VirtualAlloc でコミットしたような場合ても、アクセスしてはじめて、ページフォールトを起こしながら RAM 使用量が増えていました(全バイトへのアクセスで、ページフォルトが 12 回、RAM 使用量が 48 KB 増加)。

    2006年9月24日 4:07
  • > はじめてアクセスされるときにページフォールトが発生しない状況発生させようとしていた

    この状況を実現するには、VirtualLock を利用するのが良さそうです。

    VirtualLock の説明には、「The VirtualLock function locks the specified region of the process's virtual address space into physical memory, ensuring that subsequent access to the region will not incur a page fault.」と書かれています。

    まず、VirtualAlloc でMEM_COMMIT してページを確保、次に VirtualLock してみると如何でしょうか?

    (MEM_COMMITしていないといけないのは、VirtualLockの制約です。このあたりのこともヘルプに書かれています) 

     

    2006年9月25日 9:32
  • コメントありがとうございます。

    私もヘルプを見たところ、VirtualAlloc のヘルプの"コミット済み"状態の説明のところに、「このページの読み取りまたは書き込みを最初に試みた場合にのみ、システムは各コミット済みページを初期化し、物理メモリへロードします。」と書いてありました。MEM_PHYSICAL というフラグもあり、Address Windowing Extentions のときにのみ指定できるようです。

    そこで、

    > まず、VirtualAlloc でMEM_COMMIT してページを確保、次に VirtualLock してみると如何でしょうか?

    についてですが、初回アクセス時にはページフォールトが発生しなくなったものの、VirtualLock 時にページフォールトが発生していました。これはヘルプ通りの挙動といえそうです。

    話を元に戻してまとめますと、少なくとも AWE を使わないなら、「PagefileUsage や PeakPagefileUsage が、コミット時に RAM に割り当てられ、ページアウトされたことのないページ分を除外してカウントするのでは」という心配は不要だと、間接的ながらいいきれたと思います。そういうカウントは意味がなさそうなので、可能性はそもそも低かったのですが…

    ありがとうございました。

    2006年9月26日 23:46