Linux에서 메모리 사용을 올바르게 결정


63

나는에서보고하고 결과의 일부에 조금 혼란 스러워요 PS무료 .

내 서버에서이 결과는 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

리눅스가 메모리를 관리하는 방법에 대한 나의 이해는 디스크 사용을 RAM에 저장하여 각 후속 액세스가 더 빠르다는 것입니다. 이것이 "캐시 된"열로 표시되어 있다고 생각합니다. 또한 다양한 버퍼가 RAM에 저장되며 "버퍼"열에 표시됩니다.

따라서 올바르게 이해하면 "실제"사용은 "-/ + buffers / cache"의 "사용 된"값 또는이 경우 561로 간주됩니다.

모든 것이 정확하다고 가정하면, 나를 던지는 부분은의 결과입니다 ps aux.

ps결과 에 대한 나의 이해는 6 번째 열 (RSS)이 프로세스가 메모리에 사용하는 크기를 킬로바이트 단위로 나타냅니다.

따라서이 명령을 실행할 때 :

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

결과가 "-/ + buffers / cache"의 "used"열이 아니어야합니까 free -m?

그렇다면 리눅스에서 프로세스의 메모리 사용량을 어떻게 올바르게 결정할 수 있습니까? 분명히 내 논리에 결함이 있습니다.


이 질문은 매우 인기 htop가 있으며 다른 날에 한 비슷한 질문 에 대한 저자 의 답변을 공유해야한다고 생각 합니다 ... / proc / meminfo에서 메모리 사용량을 계산하는 방법 (예 : htop)
tgogos

답변:


57

정확히 같은 질문은 며칠 전에 serverfault 에서 요청되었습니다.

리눅스 가상 메모리 시스템은 그렇게 간단하지 않습니다. 모든 RSS 필드를 추가하고에서보고 used한 값을 가져올 수는 없습니다 free. 여기에는 여러 가지 이유가 있지만 가장 큰 몇 가지를하겠습니다.

  • 프로세스가 분기되면 부모와 자식 모두 동일한 RSS로 표시됩니다. 그러나 리눅스 copy-on-write는 두 프로세스가 실제로 동일한 메모리를 사용하도록 채택 합니다. 프로세스 중 하나가 메모리를 수정하는 경우에만 실제로 복제됩니다. 따라서이 free숫자는 topRSS 합계 보다 작습니다 .

  • RSS 값은 공유 메모리를 포함하지 않습니다. 공유 메모리는 하나의 프로세스에서 소유 top하지 않으므로 RSS에 포함하지 마십시오. 따라서이 free숫자는 topRSS 합계 보다 큽니다 .


1
이것은 지금까지 스택 교환 사이트에서 얻은 최고의 답변입니다. 구체적으로 내가 알고 싶은 것. 프로세스 포크를 작성한 프로그램을 다루고 있기 때문에 상황에 특히 정확하지만 대부분의 사용 공간은 사용하는 라이브러리에 있습니다.
GoldenNewby

이 답변의 문제점은 RSS와 SHR의 합을 계산하면 종종 사용되는 메모리보다 훨씬 적은 양을 제공한다는 것입니다. 예를 들어 VPS에서 사용 된 메모리는 380MB이고 모든 RSS와 SHR의 합은 90MB입니다.
user239558

2
@ user239558 대답에서 언급했듯이 숫자가 합산되지 않는 많은 이유가 있습니다. 그중 2 개만 나열했습니다. 다른 숫자가 많이 있습니다. 캐시, 슬래브, 거대한 페이지 등
Patrick

2
아마 몇 년 후에 당신이 이것에 대답 한 후에도 여전히 적어도 하나의 혼란이 있습니다. RSS 값에는 공유 메모리 가 포함되어 있지 않지만 이 답변 은 "해당 라이브러리의 페이지가 실제로 메모리에있는 한 공유 라이브러리의 메모리를 포함합니다"라고 답했습니다 . 이제 어느 쪽을 믿어야
할지 모르겠습니다.

1
@Naitree "공유 라이브러리"! = "공유 메모리". 공유 메모리 같은 물건 shmget이나 mmap. 메모리 관련 문구는 매우 까다 롭습니다. 잘못된 장소에서 잘못된 단어를 사용하면 문장의 의미를 완전히 망칠 수 있습니다.
Patrick

30

합산되는 메모리 번호를 찾고 있다면 smem을 살펴보십시오 .

smem은 Linux 시스템의 메모리 사용량에 대한 수많은 보고서를 제공 할 수있는 도구입니다. 기존 도구와 달리 smem은 비례 세트 크기 (PSS)를보고 할 수 있으며 이는 가상 메모리 시스템의 라이브러리 및 응용 프로그램에서 사용하는 메모리 양을보다 의미있게 나타냅니다.

실제 메모리의 많은 부분은 일반적으로 여러 응용 프로그램간에 공유되므로 RRS (Resident Set Size)라고하는 표준 메모리 사용량 측정은 메모리 사용량을 과대 평가합니다. 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그 의미의 IT를 추가합니다. 우리는 userland 프로세스에 대해 총 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 

따라서 1Gb RAM = 654Mb 사용자 영역 프로세스 + 346Mb 커널 mem + 16Mb 비어 있음
(주거나 몇 Mb)

전체 메모리의 약 절반이 캐시 (494Mb)에 사용됩니다.

보너스 질문 : 여기서 사용자 랜드 캐시와 커널 캐시는 무엇입니까?


시각적 인 시도를위한 btw :

# smem  --pie=name

여기에 이미지 설명을 입력하십시오


14

정말 좋은 도구는 pmap특정 프로세스의 현재 메모리 사용량을 나열합니다.

pmap -d PID

이에 대한 자세한 내용은 매뉴얼 페이지를 참조 man pmap하고 모든 SysAdmin이 알아야 할 20 개의 Linux 시스템 모니터링 도구를 참조하십시오.이 도구에는 Linux 상자에 대한 정보를 얻기 위해 항상 사용하는 훌륭한 도구가 나열되어 있습니다.


그것은 매우 멋진 도구이지만 실제로 내 문제를 해결하지는 못합니다. 서버에서 "실제"메모리 사용량을 효과적으로 결정하는 방법을 알아 내려고 노력 중입니다.
GoldenNewby

3
@GoldenNewby 프로세스의 "실제"메모리 사용량과 같은 것은 없습니다. 시스템의 실제 메모리 사용량이 free알려줍니다.
Gilles

pmap -x PID또한 RSS 열을 포함하는데, 프로세스의 RSS 합계 (예 : via를 통해 top발생) 를 파악 하는 데 매우 유용합니다 .
maxschlepzig

10

상단을 실행 h하고 도움말을 누른 다음 f필드를 추가하십시오. 다음 필드를 추가 할 수 있습니다.

  • RSS 응용 프로그램에서 사용중인 실제 메모리 양
  • CODE 프로세스 실행 코드에서 사용중인 총 메모리 양
  • DATA -프로세스 데이터 및 스택 전용의 총 메모리 양 (KB)

이 3 개 사이에는 꽤 정확한 결과가 있어야합니다. htop또는 내가 권장하는 상위 항목에 대해보다 자세한 교체를 사용할 수도 있습니다 atop.

편집 : 정말 자세한 정보를 원한다면 거의 잊었습니다. PID를 찾고 다음 파일을 cat하십시오.

PID=123

cat /proc/123/status

편집 2 : 그것을 찾거나 책을 가질 수 있다면 :

Linux 성능 최적화 : Linux 성능 도구에 대한 실습 안내서

-5 장 : 성능 도구 : 프로세스 별 메모리 섹션이 있습니다. 원하는 정보보다 훨씬 많은 정보가 있습니다.


기본적으로 프로세스의 RSS 크기가 있습니다. Top은 내 예제에서 "ps aux"와 동일한 결과를 제공합니다. 제 질문은, 모든 프로세스의 결합 된 RSS가 전체 서버의 "활성"메모리 사용량보다 훨씬 높다는 것입니다.
GoldenNewby

5

ps각 프로세스에서 사용되는 메모리 양을 제공합니다. 해당 메모리 중 일부는 mmapped 파일이며 캐시에서 계산됩니다. 해당 메모리 중 일부 (특히 코드)는 다른 프로세스와 공유되므로 RSS 값을 더하면 여러 번 계산됩니다.

“이 프로세스가 얼마나 많은 메모리를 사용합니까?”에 대한 정답은 없습니다. 프로세스에만 의존하지 않고 환경에도 의존하기 때문입니다. 프로세스의 "메모리 사용량"이라고하는 여러 가지 값이 있으며 서로 다른 값을 계산하기 때문에 일치하지 않거나 합산되지 않습니다.


4

다른 사람들이 올바르게 지적했듯이 프로세스가 사용하는 실제 메모리, 공유 영역 및 mmap 파일 및 기타 등등을 처리하는 것은 어렵습니다.

실험자라면 valgrind 및 massif를 실행할 수 있습니다 . 일반 사용자에게는 약간 무거울 수 있지만 시간이 지남에 따라 응용 프로그램의 메모리 동작에 대한 아이디어를 얻을 수 있습니다. 응용 프로그램 malloc ()이 정확히 필요한 것이라면 프로세스의 실제 동적 메모리 사용량을 잘 표현할 수 있습니다. 그러나이 실험은 "중독"될 수 있습니다.

문제를 복잡하게하기 위해 Linux에서는 메모리 를 과다 커밋 할 수 있습니다 . 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 $!

16GB 미만의 RAM이 장착 된 시스템에서이 기능을 실행하면 16GB의 메모리 만 확보 할 수 있습니다! (아니 정말).

의 공지 사항 top당신은 16.004G로 "VIRT"를 볼 수 있지만 %의 MEM은 0.0입니다

valgrind로 이것을 다시 실행하십시오.

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

그리고 massif는 "모든 allocs () = 16GB의 합"이라고 말합니다. 별로 흥미롭지 않습니다.

그러나 제정신 프로세스 에서 실행하는 경우 :

# 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 () 및 메모리의 LOTS를 터치하면 메모리가 디스크로 스왑 될 때까지. 따라서 할당 된 메모리가 이제 RSS를 초과합니다. 여기서 VMSize는 무언가를 알려주기 시작할 수 있습니다 (프로세스는 실제로 RAM에있는 것보다 많은 메모리를 소유합니다). 그러나 여전히 공유 페이지 인 VM과 스왑 된 데이터 인 VM을 구별하기는 여전히 어렵습니다.

valgrind / massif가 흥미로운 곳입니다. 페이지 상태에 관계없이 의도적으로 할당 한 내용이 표시 됩니다.


질문이 있습니다. mlock ()이 모든 mmap'ed 파일 인 프로세스를 가지고 있습니다. 이 메모리가 얼마나 많이 사용되는지 결정하는 방법이 있습니까? 예를 들어 지난 몇 분 동안 읽거나 쓴 메모리의 양은 얼마입니까?
Michael Martinez

2

이것을보십시오 : 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}'

size에 의해보고 된 ps실제 메모리 사용에 약간의 관계를 가지고있다. 메모리가 반드시 할당 될 필요는없는 각 프로세스의 가상 크기입니다. 또한 할당 된 일부 세그먼트는 포함되지 않습니다.
Matt

-2

사용자가 얼마나 많은 메모리를 사용하는지 보여줄 것입니다.

#!/bin/bash
total_mem=0

printf "%-10s%-10s\n" User MemUsage

while read u m
do
        [[ $old_user != $u ]] && {  printf "%-10s%-0.1f\n" $old_user $total_mem;
                                    total_mem=0; }
        total_mem="$(echo $m + $total_mem | bc)"
        old_user=$u

done < <(ps --no-headers -eo user,%mem| sort -k1)

#EOF

-3

이 명령을 사용하여 메모리 사용률을 %로 찾으십시오.

사용 된 메모리 :

grep Mem | awk '{print $3/$2 * 100.0}'

여유 메모리

grep Mem | awk '{print $4/$2 * 100.0}'

3
으 아아아 아아아 아아아 grep그냥 입력을 기다리고 앉아있을 것입니다.
mattdm

1
이 있었어야free -m | grep Mem | awk '{print $3/$2 * 100.0}'
vjangus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.