Câu trả lời:
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:
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.
top
lệnh. Hệ thống này không có bất kỳ trao đổi, swapon --show
trả 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 ...
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ế.
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:
mmap
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;
}
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:
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 signal
là SIGKILL , được gửi bởi kẻ giết người hết bộ nhớ Linux .
Giải thích đầu ra:
printf '0x%X\n' 0x40009A4 KiB ~= 64GiB
( ps
các giá trị được tính bằng KiB) sau mmap.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.8388608 KiB == 8GiB
giá trị của các trang. Do đó, RSS tăng chính xác 8GIB lên8390256 KiB == 8388608 KiB + 1648 KiB
Xem thêm: /unix/35129/need-explanation-on-resident-set-size-virtual-size
Nhật ký sát thủ OOM
Các dmesg
lệ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 865
quá 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 oom
lạ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.
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.
Chúng không được quản lý, nhưng được đo lường và có thể bị giới hạn (xem getrlimit
cuộ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/maps
và tình trạng của nó (bao gồm cả tiêu thụ bộ nhớ) thrucat /proc/1234/status