RSS và VSZ trong quản lý bộ nhớ Linux là gì


Câu trả lời:


498

RSS là Kích thước cài đặt thường trú và được sử dụng để hiển thị dung lượng bộ nhớ được phân bổ cho quá trình đó và trong RAM. Nó không bao gồm bộ nhớ được hoán đổi. 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ớ. Nó bao gồm tất cả bộ nhớ stack và heap.

VSZ là Kích thước bộ nhớ ảo. Nó bao gồm tất cả bộ nhớ mà quá trình có thể truy cập, bao gồm bộ nhớ được hoán đổi, bộ nhớ được phân bổ, nhưng không được sử dụng và bộ nhớ từ các thư viện chia sẻ.

Vì vậy, nếu tiến trình A có nhị phân 500K và được liên kết với 2500K thư viện dùng chung, có 200K phân bổ stack / heap trong đó 100K thực sự nằm trong bộ nhớ (phần còn lại được hoán đổi hoặc không sử dụng) và nó chỉ thực sự tải 1000K thư viện dùng chung và 400K nhị phân của chính nó sau đó:

RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K

Do một phần của bộ nhớ được chia sẻ, nhiều quy trình có thể sử dụng nó, vì vậy nếu bạn cộng tất cả các giá trị RSS, bạn có thể dễ dàng kết thúc với nhiều dung lượng hơn hệ thống của mình.

Bộ nhớ được phân bổ cũng có thể không có trong RSS cho đến khi nó thực sự được sử dụng bởi chương trình. Vì vậy, nếu chương trình của bạn phân bổ một loạt bộ nhớ lên trước, sau đó sử dụng nó theo thời gian, bạn có thể thấy RSS tăng lên và VSZ giữ nguyên.

Ngoài ra còn có PSS (kích thước thiết lập tỷ lệ). Đây là một biện pháp mới hơn để theo dõi bộ nhớ dùng chung theo tỷ lệ được sử dụng bởi quy trình hiện tại. Vì vậy, nếu có hai quy trình sử dụng cùng một thư viện chia sẻ từ trước:

PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K

Tất cả các luồng đều chia sẻ cùng một không gian địa chỉ, do đó RSS, VSZ và PSS cho mỗi luồng giống hệt với tất cả các luồng khác trong quy trình. Sử dụng ps hoặc top để xem thông tin này trong linux / unix.

Có nhiều cách hơn thế, để tìm hiểu thêm kiểm tra các tài liệu tham khảo sau:

Cũng thấy:


17
Tôi tin RSS không bao gồm bộ nhớ từ các thư viện liên kết động. Nếu có 3 quy trình sử dụng libxml2.so, thư viện dùng chung sẽ được tính trong mỗi RSS của họ, vì vậy tổng số RSS của họ sẽ nhiều hơn bộ nhớ thực tế được sử dụng.
nfm

1
Đúng rồi. Tôi đã sửa câu trả lời của mình, cảm ơn vì đã ngẩng cao đầu.
jmh

Tôi đang sử dụng Ubuntu 16.04 và có một quy trình java có 1.2G RES và 4.5G VIRT hiển thị từ toplệnh. Hệ thống này không có bất kỳ trao đổi, swapon --showtrả lại không có gì. Làm thế nào để bạn giải thích điều này? Nếu vsz là trao đổi + thư viện chia sẻ, trong trường hợp này, thư viện chia sẻ vượt quá 3,3G? Có thể không? Thực sự bối rối ...
Aaron Wang

Tôi không thực sự chắc chắn. Hãy xem câu trả lời này về việc sử dụng bộ nhớ ảo Java: stackoverflow.com/a/561450/622115 . Phiên bản ngắn: VSZ có thể bao gồm không gian heap được phân bổ và không được sử dụng cũng như các tệp ánh xạ bộ nhớ.
jmh

Tuyệt quá. Chỉ cần thêm một cái gì đó. nếu bạn malloc (100KB), thì thực tế chỉ sử dụng 1KB. Rss là 1K và vsz là 100K, ngay cả khi không có trao đổi ở đây.
keniee van

53

RSS là Kích thước cài đặt thường trú (bộ nhớ lưu trữ vật lý - hiện đang chiếm dung lượng trong bộ nhớ vật lý của máy) và VSZ là Kích thước bộ nhớ ảo (không gian địa chỉ được phân bổ - địa chỉ này được phân bổ trong bản đồ bộ nhớ của quy trình, nhưng không nhất thiết phải có bộ nhớ thực tế đằng sau tất cả ngay bây giờ).

Lưu ý rằng trong những ngày này của các máy ảo thông thường, bộ nhớ vật lý từ quan điểm của máy có thể không thực sự là bộ nhớ vật lý thực tế.


Tâm cung cấp nhiều thông tin hơn những gì viết tắt là viết tắt của?
Pithikos

10

Ví dụ runnable tối thiểu

Để điều này có ý nghĩa, bạn phải hiểu những điều cơ bản của phân trang: Làm thế nào để phân trang x86 hoạt động? và đặc biệt là HĐH có thể phân bổ bộ nhớ ảo thông qua các bảng trang / lưu giữ bộ nhớ trong của nó (bộ nhớ ảo VSZ) trước khi nó thực sự có bộ lưu trữ dự phòng trên RAM hoặc đĩa (bộ nhớ lưu trữ RSS).

Bây giờ để quan sát điều này trong thực tế, hãy tạo một chương trình:

  • phân bổ RAM nhiều hơn bộ nhớ vật lý của chúng tôi với mmap
  • ghi một byte trên mỗi trang để đảm bảo rằng mỗi trang đó đi từ bộ nhớ chỉ ảo (VSZ) sang bộ nhớ thực sự được sử dụng (RSS)
  • kiểm tra mức sử dụng bộ nhớ của quy trình bằng một trong các phương pháp được đề cập tại: Sử dụng bộ nhớ của quy trình hiện tại trong C

C chính

#define _GNU_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

typedef struct {
    unsigned long size,resident,share,text,lib,data,dt;
} ProcStatm;

/* /programming/1558402/memory-usage-of-current-process-in-c/7212248#7212248 */
void ProcStat_init(ProcStatm *result) {
    const char* statm_path = "/proc/self/statm";
    FILE *f = fopen(statm_path, "r");
    if(!f) {
        perror(statm_path);
        abort();
    }
    if(7 != fscanf(
        f,
        "%lu %lu %lu %lu %lu %lu %lu",
        &(result->size),
        &(result->resident),
        &(result->share),
        &(result->text),
        &(result->lib),
        &(result->data),
        &(result->dt)
    )) {
        perror(statm_path);
        abort();
    }
    fclose(f);
}

int main(int argc, char **argv) {
    ProcStatm proc_statm;
    char *base, *p;
    char system_cmd[1024];
    long page_size;
    size_t i, nbytes, print_interval, bytes_since_last_print;
    int snprintf_return;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 0x10000;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }
    if (argc < 3) {
        print_interval = 0x1000;
    } else {
        print_interval = strtoull(argv[2], NULL, 0);
    }
    page_size = sysconf(_SC_PAGESIZE);

    /* Allocate the memory. */
    base = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );
    if (base == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Write to all the allocated pages. */
    i = 0;
    p = base;
    bytes_since_last_print = 0;
    /* Produce the ps command that lists only our VSZ and RSS. */
    snprintf_return = snprintf(
        system_cmd,
        sizeof(system_cmd),
        "ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == \"%ju\") print}'",
        (uintmax_t)getpid()
    );
    assert(snprintf_return >= 0);
    assert((size_t)snprintf_return < sizeof(system_cmd));
    bytes_since_last_print = print_interval;
    do {
        /* Modify a byte in the page. */
        *p = i;
        p += page_size;
        bytes_since_last_print += page_size;
        /* Print process memory usage every print_interval bytes.
         * We count memory using a few techniques from:
         * /programming/1558402/memory-usage-of-current-process-in-c */
        if (bytes_since_last_print > print_interval) {
            bytes_since_last_print -= print_interval;
            printf("extra_memory_committed %lu KiB\n", (i * page_size) / 1024);
            ProcStat_init(&proc_statm);
            /* Check /proc/self/statm */
            printf(
                "/proc/self/statm size resident %lu %lu KiB\n",
                (proc_statm.size * page_size) / 1024,
                (proc_statm.resident * page_size) / 1024
            );
            /* Check ps. */
            puts(system_cmd);
            system(system_cmd);
            puts("");
        }
        i++;
    } while (p < base + nbytes);

    /* Cleanup. */
    munmap(base, nbytes);
    return EXIT_SUCCESS;
}

GitHub ngược dòng .

Biên dịch và chạy:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
sudo dmesg -c
./main.out 0x1000000000 0x200000000
echo $?
sudo dmesg

Ở đâu:

  • 0x1000000000 == 64GiB: gấp 2 lần RAM vật lý của máy tính của tôi là 32GiB
  • 0x200000000 == 8GiB: in bộ nhớ mỗi 8GiB, vì vậy chúng tôi sẽ nhận được 4 bản in trước khi gặp sự cố ở khoảng 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory: cần thiết cho Linux để cho phép chúng tôi thực hiện cuộc gọi mmap lớn hơn RAM vật lý: bộ nhớ tối đa mà malloc có thể phân bổ

Đầu ra chương trình:

extra_memory_committed 0 KiB
/proc/self/statm size resident 67111332 768 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 1648

extra_memory_committed 8388608 KiB
/proc/self/statm size resident 67111332 8390244 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 8390256

extra_memory_committed 16777216 KiB
/proc/self/statm size resident 67111332 16778852 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 16778864

extra_memory_committed 25165824 KiB
/proc/self/statm size resident 67111332 25167460 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 25167472

Killed

Trạng thái thoát:

137

mà theo quy tắc số tín hiệu 128 + có nghĩa là chúng ta có số tín hiệu 9, có nghĩa man 7 signalSIGKILL , được gửi bởi kẻ giết người hết bộ nhớ Linux .

Giải thích đầu ra:

  • Bộ nhớ ảo VSZ không đổi tại printf '0x%X\n' 0x40009A4 KiB ~= 64GiB( pscác giá trị được tính bằng KiB) sau mmap.
  • RSS "sử dụng bộ nhớ thực" chỉ tăng một cách lười biếng khi chúng ta chạm vào các trang. Ví dụ:
    • trên bản in đầu tiên, chúng tôi có extra_memory_committed 0, có nghĩa là chúng tôi chưa chạm vào bất kỳ trang nào. RSS là một phần nhỏ 1648 KiBđã được phân bổ cho khởi động chương trình bình thường như vùng văn bản, toàn cầu, v.v.
    • trên bản in thứ hai, chúng tôi đã viết lên 8388608 KiB == 8GiBgiá trị của các trang. Do đó, RSS tăng chính xác 8GIB lên8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS tiếp tục tăng theo gia số 8GiB. Bản in cuối cùng cho thấy khoảng 24 GiB bộ nhớ và trước khi có thể in 32 GiB, kẻ giết người OOM đã giết quá trình

Xem thêm: /unix/35129/need-explanation-on-resident-set-size-virtual-size

Nhật ký sát thủ OOM

Các dmesglệnh của chúng tôi đã hiển thị nhật ký sát thủ OOM.

Một cách giải thích chính xác của những người đã được hỏi tại:

Dòng đầu tiên của nhật ký là:

[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

Vì vậy, chúng ta thấy điều thú vị đó là daemon MongoDB luôn chạy trong máy tính xách tay của tôi trên nền tảng đầu tiên kích hoạt kẻ giết người OOM, có lẽ là khi người nghèo đang cố phân bổ bộ nhớ.

Tuy nhiên, kẻ giết người OOM không nhất thiết phải giết người đánh thức nó.

Sau khi gọi, kernel in một bảng hoặc các quy trình bao gồm oom_score:

[ 7283.479292] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 7283.479303] [    496]     0   496    16126        6   172032      484             0 systemd-journal
[ 7283.479306] [    505]     0   505     1309        0    45056       52             0 blkmapd
[ 7283.479309] [    513]     0   513    19757        0    57344       55             0 lvmetad
[ 7283.479312] [    516]     0   516     4681        1    61440      444         -1000 systemd-udevd

và xa hơn nữa chúng ta thấy rằng chính chúng ta main.outđã bị giết trong lần cầu khẩn trước đó:

[ 7283.479871] Out of memory: Kill process 15665 (main.out) score 865 or sacrifice child
[ 7283.479879] Killed process 15665 (main.out) total-vm:67111332kB, anon-rss:92kB, file-rss:4kB, shmem-rss:30080832kB
[ 7283.479951] oom_reaper: reaped process 15665 (main.out), now anon-rss:0kB, file-rss:0kB, shmem-rss:30080832kB

Nhật ký này đề cập đến score 865quá trình đó, có lẽ là điểm giết người OOM cao nhất (tệ nhất) như được đề cập tại: /unix/153585/how-does-the-oom-killer-decide-which- quá trình tiêu diệt

Cũng thú vị, mọi thứ rõ ràng đã xảy ra nhanh đến mức trước khi bộ nhớ được giải phóng, quá trình oomlại được đánh thức lại DeadlineMonitor:

[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

và lần này đã giết một số quy trình Chromium, thường là máy tính của tôi bộ nhớ bình thường:

[ 7283.481773] Out of memory: Kill process 11786 (chromium-browse) score 306 or sacrifice child
[ 7283.481833] Killed process 11786 (chromium-browse) total-vm:1813576kB, anon-rss:208804kB, file-rss:0kB, shmem-rss:8380kB
[ 7283.497847] oom_reaper: reaped process 11786 (chromium-browse), now anon-rss:0kB, file-rss:0kB, shmem-rss:8044kB

Đã thử nghiệm trong Ubuntu 19.04, nhân Linux 5.0.0.


8

Tôi nghĩ nhiều điều đã được nói, về RSS vs VSZ. Từ góc độ quản trị viên / lập trình viên / người dùng, khi tôi thiết kế / ứng dụng mã, tôi quan tâm nhiều hơn đến RSZ, (Bộ nhớ thường trú), và khi bạn tiếp tục kéo ngày càng nhiều biến số (heaped), bạn sẽ thấy giá trị này tăng lên. Hãy thử một chương trình đơn giản để xây dựng phân bổ không gian dựa trên malloc trong vòng lặp và đảm bảo bạn điền dữ liệu vào không gian malloc'd đó. RSS tiếp tục di chuyển lên. Theo như VSZ có liên quan, đó là bản đồ bộ nhớ ảo mà linux thực hiện và một trong những tính năng cốt lõi của nó xuất phát từ các khái niệm hệ điều hành thông thường. Việc quản lý VSZ được thực hiện bằng quản lý bộ nhớ ảo của kernel, để biết thêm thông tin về VSZ, xem mô tả của Robert Love trên mm_struct và vm_struct, là một phần của cấu trúc dữ liệu task_struct cơ bản trong kernel.


Bạn đang đề cập đến cuốn sách "Phát triển hạt nhân Linux" của Love?
benjimin

1

Chúng không được quản lý, nhưng được đo lường và có thể bị giới hạn (xem getrlimitcuộc gọi hệ thống, cũng trên getrlimit (2) ).

RSS có nghĩa là kích thước cài đặt thường trú (một phần của không gian địa chỉ ảo của bạn nằm trong RAM).

Bạn có thể truy vấn không gian địa chỉ ảo của tiến trình 1234 sử dụng proc (5) với cat /proc/1234/mapsvà tình trạng của nó (bao gồm cả tiêu thụ bộ nhớ) thrucat /proc/1234/status


1
Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
Maak

Tôi đã cung cấp một liên kết thứ hai. Một trong số họ sẽ còn hiệu lực
Basile Starynkevitch
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.