Xác định chính xác việc sử dụng bộ nhớ trong Linux


63

Tôi hơi bối rối về một số kết quả tôi đang thấy từ psmiễn phí .

Trên máy chủ của tôi, đây là kết quả của 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

Sự hiểu biết của tôi về cách Linux quản lý bộ nhớ, là nó sẽ lưu trữ việc sử dụng đĩa trong RAM, để mỗi lần truy cập tiếp theo nhanh hơn. Tôi tin rằng điều này được chỉ định bởi các cột "được lưu trữ". Ngoài ra, các bộ đệm khác nhau được lưu trữ trong RAM, được chỉ định trong cột "bộ đệm".

Vì vậy, nếu tôi hiểu chính xác, việc sử dụng "thực tế" được coi là giá trị "đã sử dụng" của "- / + bộ đệm / bộ đệm" hoặc 561 trong trường hợp này.

Vì vậy, giả sử tất cả những điều đó là chính xác, phần ném cho tôi là kết quả của ps aux.

Sự hiểu biết của tôi về pskết quả, là cột thứ 6 (RSS), đại diện cho kích thước tính bằng kilobyte mà quá trình sử dụng cho bộ nhớ.

Vì vậy, khi tôi chạy lệnh này:

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

Không phải kết quả là cột "đã sử dụng" của "- / + bộ đệm / bộ đệm" từ free -m?

Vậy, làm thế nào tôi có thể xác định đúng cách sử dụng bộ nhớ của một tiến trình trong Linux? Rõ ràng logic của tôi là thiếu sót.


Câu hỏi này khá phổ biến và tôi nghĩ rằng tôi nên chia sẻ câu trả lời của htoptác giả cho một câu hỏi tương tự tôi đã có vào ngày khác ... Cách tính mức sử dụng bộ nhớ từ / Proc / meminfo (như htop)
tgogos

Câu trả lời:


57

Câu hỏi chính xác này đã được hỏi trên serverfault vào một ngày khác :-)

Hệ thống bộ nhớ ảo linux không đơn giản như vậy. Bạn không thể chỉ cần thêm tất cả các trường RSS và nhận giá trị được báo cáo usedbởi free. Có nhiều lý do cho việc này, nhưng tôi sẽ đánh một vài trong số những lý do lớn nhất.

  • Khi một quá trình rẽ nhánh, cả cha mẹ và đứa trẻ sẽ hiển thị với cùng một RSS. Tuy nhiên, linux sử dụng copy-on-writeđể cả hai quá trình thực sự sử dụng cùng một bộ nhớ. Chỉ khi một trong các quy trình sửa đổi bộ nhớ thì nó mới thực sự được nhân đôi. Vì vậy, điều này sẽ khiến freesố lượng nhỏ hơn toptổng RSS.

  • Giá trị RSS không bao gồm bộ nhớ dùng chung. Bởi vì bộ nhớ dùng chung không thuộc sở hữu của bất kỳ một quá trình nào, topnên không bao gồm nó trong RSS. Vì vậy, điều này sẽ khiến freesố lượng lớn hơn toptổng RSS.


1
Đây là câu trả lời tốt nhất mà tôi nhận được trên bất kỳ trang web trao đổi ngăn xếp nào cho đến nay. Vì vậy, cụ thể những gì tôi muốn biết. Điều này đặc biệt chính xác với tình huống của tôi bởi vì tôi đang xử lý một chương trình mà tôi đã viết rằng các nhánh của quy trình, nhưng phần lớn dấu chân là trong các thư viện họ sử dụng.
GoldenNewby

Vấn đề với câu trả lời này là việc tính tổng RSS và SHR thường cho ít hơn rất nhiều so với bộ nhớ đã sử dụng. Ví dụ: trên VPS tôi có, bộ nhớ đã sử dụng là 380MB trong khi tổng của tất cả RSS và SHR là 90 MB.
user239558

2
@ user239558 Như tôi đã đề cập trong câu trả lời, có nhiều lý do các số không cộng lại, tôi chỉ liệt kê 2 trong số chúng. Có rất nhiều con số khác; bộ nhớ cache, phiến, các trang lớn, v.v.
Patrick

2
Có lẽ nhiều năm sau khi bạn trả lời, tôi vẫn còn (ít nhất) một sự nhầm lẫn. Bạn nói rằng giá trị RSS không bao gồm bộ nhớ dùng chung, nhưng câu trả lời này nói rằng "Nó bao gồm bộ nhớ từ các thư viện dùng chung miễn là các trang từ các thư viện đó thực sự nằm trong bộ nhớ". Bây giờ tôi không biết nên tin vào ai ... Có lẽ tôi đang thiếu một số khác biệt tinh tế ở đây ...
Naitree

1
@Naitree "thư viện dùng chung"! = "Bộ nhớ dùng chung". bộ nhớ chia sẻ là những thứ như shmgethoặc mmap. Các từ ngữ xung quanh bộ nhớ là rất khó khăn. Sử dụng từ sai ở vị trí sai hoàn toàn có thể làm hỏng nghĩa của câu.
Patrick

30

Nếu bạn đang tìm kiếm số bộ nhớ cộng lại, hãy xem smem :

smem là một công cụ có thể đưa ra nhiều báo cáo về việc sử dụng bộ nhớ trên các hệ thống Linux. Không giống như các công cụ hiện có, smem có thể báo cáo kích thước tập hợp tỷ lệ (PSS), đây là biểu diễn có ý nghĩa hơn về lượng bộ nhớ được sử dụng bởi các thư viện và ứng dụng trong hệ thống bộ nhớ ảo.

Do các phần lớn của bộ nhớ vật lý thường được chia sẻ giữa nhiều ứng dụng, nên số đo tiêu chuẩn sử dụng bộ nhớ được gọi là kích thước bộ thường trú (RSS) sẽ đánh giá quá cao mức sử dụng bộ nhớ. Thay vào đó, PSS đo lường "chia sẻ công bằng" của từng ứng dụng cho từng khu vực được chia sẻ để đưa ra một biện pháp thực tế.

Ví dụ ở đây:

# 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 

Vì vậy, PSScột thú vị ở đây vì nó đưa bộ nhớ chia sẻ vào tài khoản.
Không giống như RSSnó có ý nghĩa để thêm nó lên. Chúng tôi nhận được tổng cộng 654Mb cho các quy trình người dùng ở đây.

Đầu ra trên toàn hệ thống nói về phần còn lại:

# 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 

Vì vậy, tổng RAM 1Gb = 654Mb quy trình người dùng + 346Mb kernel mem + 16Mb miễn phí
(cho hoặc mất vài Mb)

Nhìn chung, khoảng một nửa bộ nhớ được sử dụng cho bộ đệm (494Mb).

Câu hỏi thưởng : bộ nhớ cache người dùng so với bộ đệm kernel ở đây là gì?


btw cho một cái gì đó thử trực quan:

# smem  --pie=name

nhập mô tả hình ảnh ở đây


14

Một công cụ thực sự tốt là pmapliệt kê việc sử dụng bộ nhớ hiện tại cho một quy trình nhất định:

pmap -d PID

Để biết thêm thông tin về nó, hãy xem trang hướng dẫn man pmapvà cũng xem 20 Công cụ giám sát hệ thống Linux Mỗi SysAdmin nên biết , danh sách các công cụ tuyệt vời mà tôi luôn sử dụng để lấy thông tin về hộp Linux của mình.


Đó là một công cụ tuyệt vời, nhưng nó không thực sự giải quyết vấn đề của tôi. Tôi đang cố gắng tìm ra cách xác định hiệu quả việc sử dụng bộ nhớ "thực tế" trên máy chủ.
GoldenNewby

3
@GoldenNewby Không có điều gì như việc sử dụng bộ nhớ thực tế của một quy trình. Việc sử dụng bộ nhớ thực tế của hệ thống là những gì freecho bạn biết.
Gilles 'SO- ngừng trở nên xấu xa'

pmap -x PIDcũng bao gồm một cột RSS thường khá hữu ích để có ý tưởng về tổng RSS của một quá trình (như được quan sát, ví dụ như thông qua topđến từ).
maxschlepzig

10

Chạy đầu, nhấn hđể được giúp đỡ sau đó fđể thêm các lĩnh vực. bạn có thể thêm các trường sau:

  • RSS dung lượng bộ nhớ vật lý mà ứng dụng đang sử dụng
  • CODE tổng dung lượng bộ nhớ mà mã thực thi của quy trình đang sử dụng
  • DATA - tổng dung lượng bộ nhớ (kb) dành riêng cho dữ liệu và ngăn xếp của quy trình

Giữa 3 bạn nên có kết quả khá chính xác. Bạn cũng có thể sử dụng thay thế chi tiết hơn cho đầu tôi khuyên htophoặc atop.

Chỉnh sửa: Hầu như quên nếu bạn muốn thông tin thực sự chi tiết. Tìm PID và cat tập tin sau.

PID=123

cat /proc/123/status

Chỉnh sửa 2: Nếu bạn có thể tìm thấy nó hoặc có cuốn sách:

Tối ưu hóa hiệu suất Linux: Hướng dẫn thực hành các công cụ hiệu suất Linux

-Có một phần Chương 5: Công cụ hiệu suất: Bộ nhớ dành riêng cho quá trình - nó có nhiều thông tin hơn bạn muốn.


Vâng, mặc định hàng đầu có kích thước RSS của quá trình. Top cho kết quả giống hệt như "ps aux" trong ví dụ của tôi. Câu hỏi của tôi là, làm thế nào mà RSS kết hợp của tất cả các quá trình lại cao hơn nhiều so với mức sử dụng bộ nhớ "hoạt động" trên toàn bộ máy chủ?
GoldenNewby

5

pscung cấp cho bạn dung lượng bộ nhớ được sử dụng bởi mỗi quá trình. Một số bộ nhớ đó là các tệp được khai thác, được tính trong bộ đệm. Một số bộ nhớ đó (đặc biệt là mã) được chia sẻ với các quy trình khác, vì vậy nếu bạn thêm các giá trị RSS, nó sẽ được tính nhiều lần.

Không có câu trả lời đúng cho quy trình này, bộ nhớ này sử dụng bao nhiêu bộ nhớ? Vì nó không phụ thuộc vào quá trình một mình mà còn phụ thuộc vào môi trường. Có nhiều giá trị khác nhau mà bạn có thể gọi là cách sử dụng bộ nhớ của bộ xử lý, và chúng không khớp hoặc cộng lại vì chúng đang đếm những thứ khác nhau.


4

Như những người khác đã chỉ ra một cách chính xác, thật khó để xử lý bộ nhớ thực được sử dụng bởi một quy trình, những gì với các khu vực được chia sẻ, và các tập tin mmap và không có gì.

Nếu bạn là người thử nghiệm, bạn có thể chạy valgrind và massif . Điều này có thể hơi nặng nề đối với người dùng thông thường nhưng bạn sẽ có ý tưởng về hành vi bộ nhớ của ứng dụng theo thời gian. Nếu một malloc () chính xác là những gì nó cần thì điều này sẽ cung cấp cho bạn một đại diện tốt về việc sử dụng bộ nhớ động thực sự của một quá trình. Nhưng thí nghiệm này có thể bị "đầu độc".

Để làm phức tạp vấn đề, Linux cho phép bạn vượt quá bộ nhớ của bạn. Khi bạn malloc () bộ nhớ, bạn nói rõ ý định tiêu thụ bộ nhớ. Nhưng phân bổ không thực sự xảy ra cho đến khi bạn viết một byte vào một trang mới của "RAM" được phân bổ của bạn. Bạn có thể tự chứng minh điều này bằng cách viết và chạy một chương trình C nhỏ như vậy:

// 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 $!

Chạy cái này trên một máy có ít hơn 16GB RAM và, thì đấy, bạn vừa ghi được 16GB bộ nhớ! (không thật sự lắm).

Lưu ý trong topbạn thấy "VIRT" là 16,004G nhưng% MEM là 0,0

Chạy lại cái này với valgrind:

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

Và massif nói "tổng của tất cả allocs () = 16GB". Vì vậy, điều đó không thú vị lắm.

NHƯNG, nếu bạn chạy nó trên một quy trình lành mạnh :

# 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

Và ở đây chúng ta thấy (rất thực nghiệm và với độ tin cậy rất cao) rằng trình biên dịch đã phân bổ 77KB của heap.

Tại sao phải cố gắng rất nhiều để có được chỉ sử dụng heap? Bởi vì tất cả các đối tượng và phần văn bản được chia sẻ mà một quá trình sử dụng (trong ví dụ này, trình biên dịch) không thú vị lắm. Chúng là chi phí liên tục cho một quá trình. Trong thực tế, các yêu cầu tiếp theo của quá trình gần như là "miễn phí".

Ngoài ra, so sánh và đối chiếu như sau:

MMAP () tệp 1GB. VMSize của bạn sẽ là 1 + GB. Nhưng Kích thước cài đặt thường trú của bạn sẽ chỉ là các phần của tệp mà bạn gây ra được phân trang (bằng cách hủy bỏ một con trỏ tới vùng đó). Và nếu bạn "đọc" toàn bộ tệp thì đến khi bạn kết thúc, hạt nhân có thể đã loại bỏ phần bắt đầu (điều này rất dễ thực hiện vì kernel biết chính xác cách thức / nơi để thay thế các trang đó nếu bị hủy bỏ một lần nữa ). Trong cả hai trường hợp, cả VMSize và RSS đều không phải là một chỉ số tốt về "mức sử dụng" bộ nhớ của bạn. Bạn chưa thực sự malloc () 'ed bất cứ điều gì.

Ngược lại, Malloc () và chạm vào NHIỀU bộ nhớ - cho đến khi bộ nhớ của bạn được hoán đổi vào đĩa. Vì vậy, bộ nhớ được phân bổ của bạn bây giờ vượt quá RSS của bạn. Tại đây, VMSize của bạn có thể bắt đầu cho bạn biết điều gì đó (quy trình của bạn sở hữu nhiều bộ nhớ hơn so với những gì thực sự nằm trong RAM của bạn). Nhưng vẫn khó phân biệt giữa VM là các trang được chia sẻ và VM được hoán đổi dữ liệu.

Đây là nơi valgrind / massif trở nên thú vị. Nó cho bạn thấy những gì bạn đã cố ý phân bổ (bất kể trạng thái của các trang của bạn).


Tôi có một câu hỏi cho bạn. Tôi đã có một quy trình xử lý tất cả các tệp của nó. Có cách nào để xác định bao nhiêu bộ nhớ này được sử dụng tích cực - bao nhiêu bộ nhớ đã được đọc hoặc ghi vào, giả sử, trong một hoặc hai phút qua?
Michael Martinez

2

Hãy thử điều này: nó sẽ cung cấp cho bạn tổng RAM thực sự được sử dụng bởi tất cả quá trình đang chạy trong MB

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}'

Các sizebáo cáo bởi pscó ít liên quan đến việc sử dụng bộ nhớ thực tế. Đó là kích thước ảo của mỗi quá trình không nhất thiết phải phân bổ bộ nhớ. Nó cũng không bao gồm một số phân khúc được phân bổ.
Matt

-2

Nó sẽ cho bạn thấy người dùng có bao nhiêu bộ nhớ ..

#!/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

Sử dụng lệnh này để tìm việc sử dụng bộ nhớ trong%.

Bộ nhớ sử dụng:

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

giải phóng bộ nhớ

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

3
Errr, điều này sẽ không làm bất cứ điều gì. grepsẽ chỉ ngồi đó chờ đầu vào.
mattdm

1
Điều này nên cófree -m | grep Mem | awk '{print $3/$2 * 100.0}'
vjangus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.