57

「ps」や「top」などのツールは、VM サイズや常駐セット サイズなど、さまざまな種類のメモリ使用量を報告します。ただし、これらはどれも「実際の」メモリ使用量ではありません。

  • プログラム コードは、同じプログラムの複数のインスタンス間で共有されます。
  • 共有ライブラリ プログラム コードは、そのライブラリを使用するすべてのプロセス間で共有されます。
  • 一部のアプリは、プロセスをフォークして、プロセスとメモリを共有します (たとえば、共有メモリ セグメントを介して)。
  • 仮想メモリ システムにより、VM サイズ レポートはほとんど役に立たなくなります。
  • プロセスがスワップ アウトされると RSS は 0 になるため、あまり役に立ちません。
  • などなど

Linux によって報告されたプライベート ダーティ RSS が、「実際の」メモリ使用量に最も近いことがわかりました。Private_Dirtyこれは、 のすべての値を合計することで取得できます/proc/somepid/smaps

しかし、他のオペレーティング システムは同様の機能を提供しますか? そうでない場合、代替手段は何ですか?特に、FreeBSD と OS X に興味があります。

4

10 に答える 10

49

OSX では、Activity Monitor が実際に非常に適切な推測を提供します。

プライベート メモリは、アプリケーションによってのみ使用される確実なメモリです。たとえば、スタック メモリと、malloc() および同等の関数/メソッド (Objective-C の alloc メソッド) を使用して動的に予約されるすべてのメモリは、プライベート メモリです。フォークすると、プライベート メモリが子と共有されますが、コピー オン ライトとマークされます。つまり、ページがどちらのプロセス (親または子) によっても変更されない限り、ページはそれらの間で共有されます。いずれかのプロセスがいずれかのページを変更するとすぐに、このページは変更される前にコピーされます。このメモリは fork の子と共有されますが (fork の子との共有できます)、「プライベート」メモリとして表示されます。最悪の場合、そのすべてのページが (遅かれ早かれ) 変更され、その後、再び各プロセスに対してプライベートになります。

共有メモリとは、現在共有されているメモリ (異なるプロセスの仮想プロセス空間で同じページが表示される) か、将来共有される可能性があるメモリ (たとえば、読み取りを共有しない理由がないため、読み取り専用メモリ) のいずれかです。 -メモリのみ)。少なくとも、Apple のいくつかのコマンド ライン ツールのソース コードを読む方法はこれです。したがって、mmap (または同じメモリを複数のプロセスにマップする同等の呼び出し) を使用してプロセス間でメモリを共有する場合、これは共有メモリになります。ただし、アプリケーションの別のインスタンスが開始された場合、既にメモリにロードされているコードを共有しない理由がないため、実行可能コード自体も共有メモリです (実行可能コード ページはデフォルトで読み取り専用です。アプリをデバッガーで)。したがって、共有メモリは実際にはアプリケーションが使用するメモリです。

実メモリは、プライベートか共有かに関係なく、現在プロセスに「割り当てられている」RAM の量です。これは、プライベートと共有の合計になる可能性がありますが、通常はそうではありません。プロセスには、現在必要なよりも多くのメモリが割り当てられている可能性があります (これにより、将来のメモリの追加要求が高速化されます) が、システムにとっては損失ではありません。別のプロセスがメモリを必要としていて空きメモリが利用できない場合、システムがスワッピングを開始する前に、その余分なメモリがプロセスから取り除かれ、別のプロセスが割り当てられます (これは高速で簡単な操作です)。そのため、次の malloc 呼び出しは多少遅くなる可能性があります。実メモリは、プライベート メモリや物理メモリよりも小さい場合もあります。これは、プロセスがシステムからメモリを要求した場合、「仮想メモリ」のみを受け取るためです。この仮想メモリは、使用しない限り、実際のメモリ ページにはリンクされません (したがって、10 MB のメモリを malloc し、その 1 バイトのみを使用すると、プロセスは割り当てられたメモリの 4096 バイトの 1 ページのみを取得します。 -残りは実際に必要な場合にのみ割り当てられます)。さらにスワップされたメモリは、実際のメモリにはカウントされない場合がありますが (これについては不明です)、共有メモリとプライベート メモリにはカウントされます。

仮想メモリは、アプリのプロセス空間で有効と見なされるすべてのアドレス ブロックの合計です。これらのアドレスは、物理メモリ (これもプライベートまたは共有) にリンクされている場合とリンクされていない場合がありますが、その場合、アドレスを使用するとすぐに物理メモリにリンクされます。既知のアドレス以外のメモリ アドレスにアクセスすると、SIGBUS が発生し、アプリがクラッシュします。メモリがスワップされると、このメモリの仮想アドレス空間は有効なままになり、それらのアドレスにアクセスするとメモリがスワップインされます。

結論:
アプリが明示的または暗黙的に共有メモリを使用しない場合、プライベート メモリは、スタック サイズ (またはマルチスレッドの場合はサイズ) と、動的メモリに対して行った malloc() 呼び出しのために、アプリが必要とするメモリの量です。その場合、共有メモリまたは実メモリをあまり気にする必要はありません。

アプリが共有メモリを使用していて、これにグラフィカル UI が含まれている場合、たとえばアプリケーションと WindowServer の間でメモリが共有されている場合は、共有メモリも確認できます。共有メモリの数値が非常に高い場合は、現時点でメモリにロードされているグラフィック リソースが多すぎることを意味している可能性があります。

アプリ開発では、実際のメモリはほとんど重要ではありません。共有とプライベートの合計よりも大きい場合、これは、システムがプロセスからメモリを奪うことを怠っていることを意味します。小さい場合は、プロセスが実際に必要とするよりも多くのメモリを要求していますが、これも悪いことではありません。要求されたメモリをすべて使用しない限り、システムからメモリを「盗む」ことにはならないからです。共有とプライベートの合計よりもはるかに小さい場合は、メモリを少し過剰に要求しているため、可能な限り少ないメモリを要求することのみを検討できます (繰り返しますが、これは悪くありませんが、コードがそうではないことがわかります)。メモリ使用量を最小限に抑えるように最適化されており、クロスプラットフォームの場合、他のプラットフォームにはそのような洗練されたメモリ処理がない可能性があります。

これらすべての情報にまだ満足できない場合は、さらに多くの情報を入手できます。ターミナルを開き、次を実行します。

sudo vmmap <pid>

はプロセスのプロセス ID です。これにより、プロセス空間内のメモリのすべてのブロックの統計が、開始アドレスと終了アドレスとともに表示されます。また、このメモリがどこから来たのか (マップされたファイル? スタック メモリ? Malloc されたメモリ? 実行可能ファイルの __DATA または __TEXT セクション?)、サイズ (KB)、アクセス権、プライベートかどうかもわかります。共有またはコピーオンライト。ファイルからマップされている場合は、ファイルへのパスも提供されます。

「実際の」RAM使用量のみが必要な場合は、使用します

sudo vmmap -resident <pid>

これで、すべてのメモリ ブロックについて、メモリ ブロックが仮想的にどのくらいの大きさで、実際に物理メモリにどれだけ存在するかが表示されます。

各ダンプの最後には、さまざまなメモリ タイプの合計を示す概要表もあります。この表は、現在私のシステムの Firefox では次のようになっています。

REGION TYPE             [ VIRTUAL/RESIDENT]
===========             [ =======/========]
ATS (font support)      [   33.8M/   2496K]
CG backing stores       [   5588K/   5460K]
CG image                [     20K/     20K]
CG raster data          [    576K/    576K]
CG shared images        [   2572K/   2404K]
Carbon                  [   1516K/   1516K]
CoreGraphics            [      8K/      8K]
IOKit                   [  256.0M/      0K]
MALLOC                  [  256.9M/  247.2M]
Memory tag=240          [      4K/      4K]
Memory tag=242          [     12K/     12K]
Memory tag=243          [      8K/      8K]
Memory tag=249          [    156K/     76K]
STACK GUARD             [  101.2M/   9908K]
Stack                   [   14.0M/    248K]
VM_ALLOCATE             [   25.9M/   25.6M]
__DATA                  [   6752K/   3808K]
__DATA/__OBJC           [     28K/     28K]
__IMAGE                 [   1240K/    112K]
__IMPORT                [    104K/    104K]
__LINKEDIT              [   30.7M/   3184K]
__OBJC                  [   1388K/   1336K]
__OBJC/__DATA           [     72K/     72K]
__PAGEZERO              [      4K/      0K]
__TEXT                  [  108.6M/   63.5M]
__UNICODE               [    536K/    512K]
mapped file             [  118.8M/   50.8M]
shared memory           [    300K/    276K]
shared pmap             [   6396K/   3120K]

これは何を教えてくれますか?たとえば、Firefox バイナリとそれがロードするすべてのライブラリには、__TEXT セクションに 108 MB のデータがありますが、現在メモリに常駐しているのはそのうちの 63 MB だけです。フォント サポート (ATS) には 33 MB が必要ですが、実際にメモリにあるのは約 2.5 MB だけです。5 MB を少し超える CG バッキング ストア (CG = コア グラフィックス) を使用します。これらは、高速描画のためにキャッシュされるウィンドウ コンテンツ、ボタン、画像、およびその他のデータである可能性が高くなります。malloc 呼び出しを介して 256 MB を要求し、現在 247 MB​​ が実際にメモリ ページにマップされています。スタック用に 14 MB のスペースが確保されていますが、現在実際に使用されているのは 248 KB のスタック スペースのみです。

vmmap には、表の上にも適切な要約があります

ReadOnly portion of Libraries: Total=139.3M resident=66.6M(48%) swapped_out_or_unallocated=72.7M(52%)
Writable regions: Total=595.4M written=201.8M(34%) resident=283.1M(48%) swapped_out=0K(0%) unallocated=312.3M(52%)

そして、これは OS X の興味深い側面を示しています。ライブラリから取得される読み取り専用メモリの場合、スワップ アウトされているか、単に割り当てられていない場合、そのメモリは何の役割も果たしません。居住者のみが存在し、居住者は存在しません。書き込み可能なメモリの場合、これは違いを生みます (私の場合、要求されたすべてのメモリの 52% が使用されておらず、割り当てられていないため、メモリの 0% がディスクにスワップアウトされています)。

その理由は単純です。マップされたファイルからの読み取り専用メモリはスワップされません。システムがメモリを必要とする場合、メモリはすでに「スワップ」されているため、現在のページは単にプロセスから削除されます。ファイルから直接マップされたコンテンツのみで構成され、ファイルがまだ存在するため、このコンテンツは必要に応じていつでも再マップできます。そうすれば、このメモリがスワップ ファイルのスペースを浪費することもありません。ファイルのコンテンツは以前にディスクに保存されていなかったため、書き込み可能なメモリのみを、削除する前にファイルにスワップする必要があります。

于 2009-12-23T19:15:34.180 に答える
10

Linux では、/proc/self/smaps に PSS (比例セット サイズ) の数値が必要な場合があります。マッピングの PSS は、RSS をそのマッピングを使用しているプロセスの数で割ったものです。

于 2011-10-12T02:08:51.500 に答える
7

トップはこれを行う方法を知っています。Debian Linux では、デフォルトで VIRT、RES、および SHR が表示されます。VIRT = スワップ + RES。解像度 = コード + データ。SHR は、別のプロセス (共有ライブラリまたは他のメモリ) と共有できるメモリです。

また、「ダーティ」メモリは、使用された、および/またはスワップされていない単なる RES メモリです。

見分けるのは難しいかもしれませんが、理解する最善の方法は、スワップしていないシステムを見ることです。次に、RES - SHR はプロセス専用メモリです。ただし、SHR 内のメモリが別のプロセスによって使用されていることを知らないため、これは適切な見方ではありません。プロセスによってのみ使用される未書き込みの共有オブジェクト ページを表す場合があります。

于 2008-09-23T01:57:15.273 に答える
7

あなたは本当にできません。

つまり、プロセス間の共有メモリ...カウントするかどうか。それを数えなければ、あなたは間違っています。すべてのプロセスのメモリ使用量の合計は、合計メモリ使用量にはなりません。それを数える場合、それを 2 回数えることになります。合計は正しくありません。

私は、RSS に満足しています。そして、あなたが本当に完全にそれに頼ることはできないことを知っています...

于 2008-11-29T18:06:25.947 に答える
6

/proc/pid/smaps からプライベート ダーティおよびプライベート クリーン RSS を取得できます。

于 2012-03-06T20:55:32.187 に答える
4

smem を参照してください。PSS情報を提供します

http://www.selenic.com/smem/

于 2014-03-10T16:26:15.413 に答える
3

これを作り直して、よりクリーンにし、bash での適切なベスト プラクティスを示し、特にawkの代わりに使用できるようにしbcました。

find /proc/ -maxdepth 1 -name '[0-9]*' -print0 | while read -r -d $'\0' pidpath; do
  [ -f "${pidpath}/smaps" ] || continue
  awk '!/^Private_Dirty:/ {next;}
       $3=="kB" {pd += $2 * (1024^1); next}
       $3=="mB" {pd += $2 * (1024^2); next}
       $3=="gB" {pd += $2 * (1024^3); next}
       $3=="tB" {pd += $2 * (1024^4); next}
       $3=="pB" {pd += $2 * (1024^5); next}
       {print "ERROR!!  "$0 >"/dev/stderr"; exit(1)}
       END {printf("%10d: %d\n", '"${pidpath##*/}"', pd)}' "${pidpath}/smaps" || break
done

私のマシンの便利な小さなコンテナーで| sort -n -k 2、出力を並べ替えると、次のようになります。

        56: 106496
         1: 147456
        55: 155648
于 2013-05-16T21:04:38.607 に答える
1

確認してください。これは gnome-system-monitor のソース コードです。1 つのプロセスによって「実際に使用されるinfo->mem」メモリは、X Server Memory( info->memxserver) と Writable Memory( ) の sum( ) であると考えられますinfo->memwritable。「Writable Memory」は、/proc/PID/smapsファイルで「 Private_Dirty」とマークされているメモリ ブロック。

Linux システム以外では、gnome-system-monitor コードによって異なる方法である可能性があります。

static void
get_process_memory_writable (ProcInfo *info)
{
    glibtop_proc_map buf;
    glibtop_map_entry *maps;

    maps = glibtop_get_proc_map(&buf, info->pid);

    gulong memwritable = 0;
    const unsigned number = buf.number;

    for (unsigned i = 0; i < number; ++i) {
#ifdef __linux__
        memwritable += maps[i].private_dirty;
#else
        if (maps[i].perm & GLIBTOP_MAP_PERM_WRITE)
            memwritable += maps[i].size;
#endif
    }

    info->memwritable = memwritable;

    g_free(maps);
}

static void
get_process_memory_info (ProcInfo *info)
{
    glibtop_proc_mem procmem;
    WnckResourceUsage xresources;

    wnck_pid_read_resource_usage (gdk_screen_get_display (gdk_screen_get_default ()),
                                  info->pid,
                                  &xresources);

    glibtop_get_proc_mem(&procmem, info->pid);

    info->vmsize    = procmem.vsize;
    info->memres    = procmem.resident;
    info->memshared = procmem.share;

    info->memxserver = xresources.total_bytes_estimate;

    get_process_memory_writable(info);

    // fake the smart memory column if writable is not available
    info->mem = info->memxserver + (info->memwritable ? info->memwritable : info->memres);
}
于 2013-09-15T17:19:49.497 に答える
1

Freebsd に言及した質問に対して、まだ誰もこれを書いていないことに驚きました:

Linux スタイルの /proc/PROCESSID/status 出力が必要な場合は、次の手順を実行してください。

mount -t linprocfs none /proc
cat /proc/PROCESSID/status

少なくとも FreeBSD 7.0 では、マウントはデフォルトでは行われませんでした (7.0 はかなり古いリリースですが、この基本的なものについては、回答がメーリング リストに隠されていました!)

于 2013-01-07T07:31:35.527 に答える