web-dev-qa-db-ja.com

プロセスの「実際の」メモリ使用量、つまりプライベートなダーティRSSを判断する方法は?

「ps」や「top」などのツールは、VM sizeやResident Set Sizeなど)のさまざまな種類のメモリ使用量を報告します。ただし、これらはいずれも「実際の」メモリ使用量ではありません。

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

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

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

45
Hongli

OSXでは、アクティビティモニターが実際に非常に良い推測を提供します。

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

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

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

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

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

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

実際のメモリは、アプリ開発にはほとんど関心がありません。共有とプライベートの合計よりも大きい場合、これはシステムがメモリをプロセスから奪い取るのが面倒であることを意味します。小さい場合、プロセスは実際に必要な量より多くのメモリを要求していますが、これも悪くはありません。要求されたメモリをすべて使用しない限り、システムからメモリを「盗む」ことはないからです。共有とプライベートの合計よりもはるかに小さい場合、少しメモリを過剰に要求しているため、可能な限り少ないメモリを要求することだけを検討することができます(これも悪くありませんが、コードはそうではないことを教えてくれます)最小限のメモリ使用量に最適化されており、クロスプラットフォームの場合、他のプラットフォームではそれほど洗練されたメモリ処理が行われない可能性があるため、たとえば、いくつかの大きなブロックではなく多くの小さなブロックを割り当てるか、メモリをより早く解放することをお勧めしますオン)。

それでもすべての情報に満足できない場合は、さらに多くの情報を取得できます。ターミナルを開いて実行します:

Sudo vmmap <pid>

ここで、プロセスのプロセスIDです。これにより、[〜#〜] every [〜#〜]プロセス空間内のメモリブロックの開始アドレスと終了アドレスの統計が表示されます。また、このメモリがどこから来たのか(マップされたファイル?スタックメモリ?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 = Core Graphics)を使用します。これらは、ウィンドウコンテンツ、ボタン、画像、および高速描画用にキャッシュされるその他のデータである可能性が最も高くなります。 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%のメモリがディスクにスワップアウトされています)

42
Mecki

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

9
Justin L.

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

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

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

6
Chris

本当にできない。

つまり、プロセス間で共有メモリを...あなたはそれを数えるつもりであるかどうか。あなたがそれを数えなければ、あなたは間違っています。すべてのプロセスのメモリ使用量の合計は、合計メモリ使用量にはなりません。あなたがそれを数えるなら、あなたはそれを二度数えようとしている-合計は正しくないだろう。

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

5
alex

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

5
abc

Smemを見てください。 PSS情報を提供します

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

3
gheese

Mincore(2)システムコールを使用します。マニュアルページを引用する:

DESCRIPTION
     The mincore() system call determines whether each of the pages in the
     region beginning at addr and continuing for len bytes is resident.  The
     status is returned in the vec array, one character per page.  Each
     character is either 0 if the page is not resident, or a combination of
     the following flags (defined in <sys/mman.h>):

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
2
BMDan

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

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

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

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

1
Arvind

これを確認してください。これはgnome-system-monitorのソースコードであり、1つのプロセスで実際に使用されるメモリ()はsum(info->mem)Xサーバーメモリ(info->memxserver)および書き込み可能メモリ(info->memwritable)、「Writable Memory」は、「Private_Dirty = "in / proc/PID/smapsファイル。

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);
}
1