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가 메모리를 관리하는 방법에 대해 내가 이해한 바는 디스크 사용량을 RAM에 저장하므로 이후의 각 액세스가 더 빨라진다는 것입니다. 나는 이것이 "캐시된" 열에 의해 표시된다고 믿습니다. 또한 "버퍼" 열에 표시된 다양한 버퍼가 RAM에 저장됩니다.

따라서 제가 올바르게 이해했다면 "실제" 사용량은 "-/+ 버퍼/캐시"의 "사용된" 값 또는 이 경우 561로 가정됩니다.

따라서 모든 것이 정확하다고 가정하면 나를 던지는 부분은 ps aux.

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

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

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

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

그렇다면 Linux에서 프로세스의 메모리 사용량을 어떻게 적절하게 확인할 수 있습니까? 분명히 내 논리에 결함이 있습니다.

답변1

내 답변을 뻔뻔하게 복사/붙여넣기서버 결함얼마 전 :-)

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

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

  • RSS 값에는 공유 메모리가 포함되지 않습니다. 공유 메모리는 어느 하나의 프로세스가 소유하지 않기 때문에 topRSS에 포함하지 않습니다.
    이로 인해 free숫자가 RSS 합계보다 커집니다 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)에 사용됩니다.

보너스 질문: 여기서 유저랜드 캐시와 커널 캐시는 무엇인가요?


btw 시각적인 시도를 위해:

# smem  --pie=name

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

답변3

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

pmap -d PID

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

답변4

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

실험자라면 다음을 실행할 수 있습니다.발그린드와 마시프. 일반 사용자에게는 다소 부담스러울 수 있지만 시간이 지남에 따라 애플리케이션의 메모리 동작에 대한 아이디어를 얻을 수 있습니다. 애플리케이션 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가 됩니다! (아니 정말).

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

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

이것이 valgrind/massif가 흥미로운 부분입니다. 그것은 당신이 무엇을 가지고 있는지 보여줍니다의도적으로(페이지 상태에 관계없이) 할당됩니다.

관련 정보