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

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

내가 본 결과 중 일부가 약간 혼란스럽습니다.메모그리고무료.

내 서버에서는 이것이 결과입니다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가 메모리를 관리하는 방식에 대해 제가 이해한 바는 Linux가 디스크 사용량을 RAM에 저장하여 이후의 각 액세스 속도가 더 빨라진다는 것입니다. 나는 이것이 "캐시" 열로 표시된다고 생각합니다. 또한 "버퍼" 열에 표시된 것처럼 다양한 버퍼가 RAM에 저장됩니다.

따라서 제가 올바르게 이해했다면 "실제" 사용량은 "-/+ 버퍼/캐시"의 "사용된" 값이어야 하며 이 경우 561입니다.

그래서 이 모든 것이 맞다고 가정할 때, 제가 혼란스러워하는 부분은 입니다 ps aux.

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

따라서 이 명령을 실행하면 다음과 같습니다.

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

결과는 "-/+ 버퍼/캐시"의 "사용된" 열이 아니어야 합니까 free -m?

그렇다면 Linux에서 프로세스의 메모리 사용량을 올바르게 결정하는 방법은 무엇입니까? 분명히 내 논리에 뭔가 문제가 있는 것 같습니다.

답변1

내 답변의 뻔뻔한 복사/붙여 넣기서버 장애얼마 전 :-)

Linux 가상 메모리 시스템은 그렇게 간단하지 않습니다. 모든 RSS 필드를 합산하고 보고된 used값을 얻을 수는 없습니다 free. 여기에는 여러 가지 이유가 있지만 가장 중요한 몇 가지 이유를 나열하겠습니다.

  • 프로세스가 분기되면 상위 프로세스와 하위 프로세스 모두 동일한 RSS를 표시합니다. 그러나 Linux는 쓰기 중 복사를 사용하므로 두 프로세스 모두 실제로 동일한 메모리를 사용합니다. 프로세스 중 하나가 메모리를 수정하는 경우에만 실제로 복사됩니다.
    이로 인해 숫자가 RSS 합계 free보다 작아집니다 .top

  • RSS 값에는 공유 메모리가 포함되지 않습니다. 공유 메모리는 어느 하나의 프로세스에 속하지 않기 때문에 topRSS에 포함되지 않습니다.
    이로 인해 숫자가 RSS 합계 free보다 커집니다 .top

이 숫자가 합산되지 않는 데에는 다른 많은 이유가 있습니다. 이 답변은 메모리 관리가 매우 복잡하며 전체 메모리 사용량을 얻기 위해 단일 값을 더하거나 뺄 수 없다는 것을 보여줍니다.

답변2

합산되는 메모리 번호를 찾고 있다면 다음을 확인하세요.스엠:

smem은 Linux 시스템 메모리 사용량에 대한 광범위한 보고서를 제공하는 도구입니다. 기존 도구와 달리 smem은 가상 메모리 시스템의 라이브러리와 애플리케이션이 사용하는 메모리 양을 보다 의미 있게 표현하는 PSS(Proportional Set Size)를 보고할 수 있습니다.

대부분의 실제 메모리는 일반적으로 여러 애플리케이션에서 공유되므로 RSS(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여기서는 사용자 모드 프로세스를 위해 총 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 커널 메모리 + 16Mb 여유 공간
(몇 Mb 정도 제공 또는 감소)

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

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


그나저나, 일부 시각적 시도의 경우:

# smem  --pie=name

여기에 이미지 설명을 입력하세요.

답변3

매우 좋은 도구는 pmap프로세스의 현재 메모리 사용량을 나열하는 것입니다.

pmap -d PID

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

답변4

다른 사람들이 올바르게 지적했듯이 프로세스에서 사용하는 실제 메모리, 공유 영역, 매핑된 파일 등을 추적하는 것은 어렵습니다.

실험자라면 다음을 실행할 수 있습니다.월그린드와 플롯. 일반 사용자에게는 약간 번거로울 수 있지만 시간이 지나면 애플리케이션의 메모리 동작을 이해하게 될 것입니다. 애플리케이션이 정확히 필요한 것을 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 $!

RAM이 16GB 미만인 컴퓨터에서 이 프로그램을 실행해 보세요! 16GB RAM이 생겼습니다! (아니 정말).

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"라고 말합니다. 그래서 별로 흥미롭지 않습니다.

하지만 만약 당신이합리적인프로세스:

# 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 파일. VMS 크기는 1+GB입니다. 그러나 상주 세트 크기는 (해당 영역에 대한 포인터를 역참조하여) 페이징을 발생시키는 파일의 부분일 뿐입니다. 전체 파일을 "읽는" 경우 끝에 도달할 때 커널이 시작 부분을 페이지 아웃했을 수 있습니다. 이는 커널이 해당 페이지가 다시 역참조될 경우 해당 페이지를 교체하는 방법/위치를 정확히 알고 있기 때문에 쉽습니다. ). 두 경우 모두, VMSize와 RSS는 메모리 "사용"을 제대로 나타내지 못합니다. 실제로는 아직 malloc() 아무것도 하지 않았습니다.

대조적으로, Malloc()은 메모리가 디스크로 교체될 때까지 많은 메모리를 차지합니다. 따라서 할당된 메모리는 이제 RSS를 초과합니다. 여기서 VMSize가 무언가를 알려주기 시작할 수 있습니다(프로세스에는 실제로 RAM에 있는 것보다 더 많은 메모리가 있습니다). 그러나 페이지를 공유하는 가상 머신과 데이터를 교환하는 가상 머신을 구별하는 것은 여전히 ​​어렵습니다.

이것이 valgrind/massif가 흥미로운 부분입니다. 그것은 당신에게 보여줍니다의도적으로할당됨(페이지 상태에 관계없음)

관련 정보