web-dev-qa-db-ja.com

Linuxでのメモリ使用量を正しく決定する

psfreeで表示される結果の一部について少し混乱しています。

私のサーバーでは、これはfree -mの結果です

[root@server ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          2048       2033         14          0         73       1398
-/+ buffers/cache:        561       1486
Swap:         2047         11       2036

Linuxがメモリを管理する方法についての私の理解は、ディスクの使用量をRAMに保存するため、その後の各アクセスがより速くなるということです。これは「キャッシュされた」列で示されていると思います。さらに、「バッファ」列に示されているさまざまなバッファがRAMに格納されます。

したがって、私が正しく理解していれば、「実際の」使用量は「-/ +バッファ/キャッシュ」の「使用済み」値、またはこの場合は561であると考えられます。

したがって、これらすべてが正しいと仮定すると、私をスローするのはps auxの結果です。

psの結果についての私の理解は、6番目の列(RSS)がプロセスがメモリに使用するキロバイト単位のサイズを表すということです。

したがって、このコマンドを実行すると:

[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52

結果はfree -mの「-/ + buffers/cache」の「used」列ではないのですか?

では、Linuxのプロセスのメモリ使用量を適切に判断するにはどうすればよいですか?どうやら私の論理には欠陥があります。

66
GoldenNewby

これexact同じ質問が serverfault 先日行われた:-)

Linuxの仮想メモリシステムはそれほど単純ではありません。すべてのRSSフィールドを合計して、usedによって報告された値をfreeで取得することはできません。これには多くの理由がありますが、最大の原因をいくつか挙げます。

  • プロセスがフォークすると、親と子の両方が同じRSSで表示されます。ただし、Linuxはcopy-on-write両方のプロセスが実際に同じメモリを使用するようにします。プロセスの1つがメモリを変更したときにのみ、実際にメモリが複製されます。したがって、これによりfreeの数値はtop RSSの合計よりも小さくなります。

  • RSS値には共有メモリは含まれません。共有メモリは1つのプロセスによって所有されていないため、topはRSSにそれを含めません。したがって、これにより、freeの数値がtop RSSの合計よりも大きくなります。

57
Patrick

合計するメモリ番号を探している場合は、 smem を参照してください。

smemは、Linuxシステムでのメモリ使用量に関する多数のレポートを提供できるツールです。既存のツールとは異なり、smemはプロポーショナルセットサイズ(PSS)を報告できます。PSSは、仮想メモリシステム内のライブラリとアプリケーションによって使用されるメモリの量のより意味のある表現です。

物理メモリの大部分は通常複数のアプリケーション間で共有されるため、常駐セットサイズ(RSS)と呼ばれるメモリ使用量の標準的な測定値は、メモリ使用量を大幅に過大評価します。代わりに、PSSは各共有領域の各アプリケーションの「フェアシェア」を測定して、現実的な測定を行います。

例えばここに:

# smem -t
  PID User     Command                         Swap      USS      PSS      RSS
...
10593 root     /usr/lib/chromium-browser/c        0    22868    26439    49364 
11500 root     /usr/lib/chromium-browser/c        0    22612    26486    49732 
10474 browser  /usr/lib/chromium-browser/c        0    39232    43806    61560 
 7777 user     /usr/lib/Thunderbird/thunde        0    89652    91118   102756 
-------------------------------------------------------------------------------
  118 4                                       40364   594228   653873  1153092 

PSSは、共有メモリを考慮しているため、ここでは興味深い列です。
RSSとは異なり、合計することには意味があります。ここでは、ユーザーランドプロセスの合計が654Mbになります。

システム全体の出力は、残りについて説明します。

# smem -tw
Area                           Used      Cache   Noncache 
firmware/hardware                 0          0          0 
kernel image                      0          0          0 
kernel dynamic memory        345784     297092      48692 
userspace memory             654056     181076     472980 
free memory                   15828      15828          0 
----------------------------------------------------------
                            1015668     493996     521672 

つまり、1 Gb RAM合計 = 654Mb ユーザーランドプロセス + 346Mb カーネルメモリ + 16Mb 自由
(与えるか、数Mbを取る)

全体でメモリの約半分がキャッシュに使用されます(494Mb)。

ボーナス質問:ユーザーランドキャッシュとカーネルキャッシュの違いは何ですか?


何か視覚的な試みのために:

# smem  --pie=name

enter image description here

31
lemonsqueeze

本当に良いツールはpmapで、特定のプロセスの現在のメモリ使用量を一覧表示します。

pmap -d PID

詳細については、man pmapのマンページを参照してください。また、Linuxに関する情報を取得するために常に使用する優れたツールの一覧である すべてのSysAdminが知っておくべき20のLinuxシステム監視ツール もご覧ください。ボックス。

14
ByteNudger

Topを実行し、hを押してヘルプを表示し、次にfを押してフィールドを追加します。次のフィールドを追加できます。

  • RSSアプリケーションが使用している物理メモリの量
  • CODEプロセスの実行可能コードが使用しているメモリの総量
  • DATA-プロセスのデータとスタック専用のメモリの総量(kb)

これら3つの間では、かなり正確な結果が得られるはずです。 htopまたはatopをお勧めします。

編集:本当に詳細な情報が必要な場合は、ほとんど忘れてしまいました。 PIDを見つけて、次のファイルをcatします。

PID=123

cat /proc/123/status

編集2:あなたがそれを見つけるか、それを本に持っている場合:

Linuxパフォーマンスの最適化:Linuxパフォーマンスツールの実践ガイド

-セクション第5章:パフォーマンスツール:プロセス固有のメモリ-セクションがあります。これには、必要以上に多くの情報があります。

10
2bc

psは、各プロセスで使用されるメモリの量を示します。そのメモリの一部はキャッシュ内でカウントされるmmappedファイルです。そのメモリの一部(特にコード)は他のプロセスと共有されるため、RSS値を合計すると、複数回カウントされます。

「このプロセスが使用するメモリの量」に対する正しい答えはありません。これは、プロセスだけに依存するのではなく、環境にも依存するためです。プロセスの「メモリ使用量」と呼ばれる可能性のあるさまざまな値があり、それらは異なるものをカウントしているため、一致または合計されません。

他の人が正しく指摘しているように、プロセスによって使用される実際のメモリ、共有領域で何が行われるか、mmapされたファイルなどでハンドルを取得することは困難です。

実験者であれば、 valgrind and massif を実行できます。これは、カジュアルなユーザーにとっては少し重くなるかもしれませんが、アプリケーションのメモリの動作について、時間の経過とともにわかります。アプリケーションmalloc()がまさにそれを必要とする場合、これはプロセスの実際の動的メモリ使用量を適切に表現します。しかし、この実験は「毒殺」される可能性があります。

問題を複雑にするために、Linuxでは overcommit メモリーを使用できます。メモリをmalloc()するときは、メモリを消費する意図を示しています。しかし、割り当てられた「RAM」の新しいページにバイトを書き込むまで、割り当ては実際には起こりません。次のような小さなCプログラムを作成して実行することで、これを自分で証明できます。

// test.c
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    void *p;
    sleep(5)
    p = malloc(16ULL*1024*1024*1024);
    printf("p = %p\n", p);
    sleep(30);
    return 0;
}

# Shell:
cc test.c -o test && ./test &
top -p $!

RAM= 16GB未満のマシンでこれを実行すると、16GBのメモリを獲得したことになります!.

topには「VIRT」が16.004Gと表示されていますが、%MEMは0.0です。

Valgrindでこれをもう一度実行します。

# Shell:
valgrind --tool=massif ./test &
sleep 36
ms_print massif.out.$! | head -n 30

そしてMassifは「すべてのallocs()の合計= 16GB」と言います。だからそれはあまり面白くない。

しかし、saneプロセスで実行した場合:

# Shell:
rm test test.o
valgrind --tool=massif cc test.c -o test &
sleep 3
ms_print massif.out.$! | head -n 30

--------------------------------------------------------------------------------
Command:            cc test.c -o test
Massif arguments:   (none)
ms_print arguments: massif.out.23988
--------------------------------------------------------------------------------


    KB
77.33^                                                                       :
     |                                                                      #:
     |                                                                :@::@:#:
     |                                                           :::::@@::@:#:
     |                                                         @:: :::@@::@:#:
     |                                                     ::::@:: :::@@::@:#:
     |                                             ::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                      :@@@@@@@@@@@@@@@@@@@@:@::@:::@:::::@:: :::@@::@:#:
     |                      :@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |              :@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |          :::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |        :::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
   0 +----------------------------------------------------------------------->Mi
     0                                                                   1.140

そしてここでは、コンパイラが77KBのヒープを割り当てたことが(非常に経験的に、非常に高い信頼度で)わかります。

なぜヒープ使用量だけを取得するために一生懸命に努力するのですかプロセスが使用するすべての共有オブジェクトとテキストセクション(この例ではコンパイラ)はそれほど興味深いものではないためです。それらはプロセスの一定のオーバーヘッドです。実際、その後のプロセスの呼び出しは、ほぼ「無料」で行われます。

また、以下を比較対照してください。

MMAP()1GBファイル。 VMSizeは1 + GBになります。しかし、常駐セットのサイズは、(その領域へのポインタを逆参照することによって)ページインされたファイルの部分のみになります。そして、ファイル全体を「読み取った」場合、最後までたどり着くまでに、カーネルは最初のページをすでにページアウトしている可能性があります(カーネルが再び逆参照された場合にこれらのページを置き換える方法/場所を正確に知っているため、これは簡単に実行できます) )。どちらの場合も、VMSizeもRSSも、メモリの「使用状況」を示す適切な指標ではありません。実際にはmalloc()を実行していません。

対照的に、メモリがディスクにスワップされるまで、Malloc()とメモリの多くに触れます。したがって、割り当てられたメモリはRSSを超えています。ここで、VMSizeが何かを伝え始める可能性があります(プロセスは、RAMに実際に存在するものよりも多くのメモリを所有しています)。しかし、共有ページであるVMと、スワップされたデータであるVMを区別することは依然として困難です。

これは、valgrind/massifが面白くなるところです。 意図的に割り当てたものを表示します(ページの状態に関係なく)。

4

これを試してください:MBで実行されているすべてのプロセスによって実際に使用されている合計RAM

ps -eo size,pid,user,command --sort -size | awk '
  { hr=$1/1024 ; printf("%13.2f Mb ",hr) } 
  { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }
  ' | awk '{total=total + $1} END {print total}'
2
Vineeth