RSS และ VSZ ในการจัดการหน่วยความจำ Linux คืออะไร ในสภาพแวดล้อมแบบมัลติเธรดวิธีการทั้งสองนี้สามารถจัดการและติดตามได้อย่างไร
RSS และ VSZ ในการจัดการหน่วยความจำ Linux คืออะไร ในสภาพแวดล้อมแบบมัลติเธรดวิธีการทั้งสองนี้สามารถจัดการและติดตามได้อย่างไร
คำตอบ:
RSS คือขนาดชุดที่อยู่อาศัยและใช้เพื่อแสดงจำนวนหน่วยความจำที่จัดสรรให้กับกระบวนการนั้นและอยู่ใน RAM ไม่รวมถึงหน่วยความจำที่เปลี่ยน มันรวมถึงหน่วยความจำจากไลบรารีที่ใช้ร่วมกันตราบใดที่หน้าจากไลบรารีเหล่านั้นอยู่ในหน่วยความจำจริง มันรวมหน่วยความจำสแต็คและกองทั้งหมด
VSZ เป็นขนาดหน่วยความจำเสมือน ซึ่งรวมถึงหน่วยความจำทั้งหมดที่กระบวนการสามารถเข้าถึงรวมถึงหน่วยความจำที่ถูกสลับหน่วยความจำที่จัดสรร แต่ไม่ได้ใช้และหน่วยความจำที่มาจากไลบรารีที่แชร์
ดังนั้นหากโพรเซส A มีไบนารี 500K และเชื่อมโยงกับไลบรารีที่แชร์ 2,500,000KK มีการจัดสรรสแต็ก / กองฮีป 200K ซึ่ง 100K นั้นอยู่ในหน่วยความจำจริง (ส่วนที่เหลือถูกเปลี่ยนเป็นหรือไม่ได้ใช้) และ 400K ของไบนารีของตัวเองแล้ว:
RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K
เนื่องจากส่วนหนึ่งของหน่วยความจำถูกแชร์กระบวนการจำนวนมากอาจใช้งานดังนั้นหากคุณรวมค่า RSS ทั้งหมดคุณสามารถจบลงด้วยพื้นที่ที่มากกว่าระบบของคุณ
หน่วยความจำที่จัดสรรไว้อาจไม่อยู่ใน RSS จนกว่าจะมีการใช้งานจริงโดยโปรแกรม ดังนั้นหากโปรแกรมของคุณจัดสรรหน่วยความจำไว้ล่วงหน้าให้ใช้เมื่อเวลาผ่านไปคุณจะเห็นว่า RSS กำลังสูงขึ้นและ VSZ ยังคงเหมือนเดิม
นอกจากนี้ยังมี PSS (ขนาดชุดสัดส่วน) นี่คือการวัดที่ใหม่กว่าซึ่งติดตามหน่วยความจำที่แชร์เป็นสัดส่วนที่ใช้โดยกระบวนการปัจจุบัน ดังนั้นหากมีสองกระบวนการที่ใช้ห้องสมุดสาธารณะเดียวกันจากก่อนหน้านี้:
PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K
เธรดทั้งหมดใช้พื้นที่แอดเดรสเดียวกันดังนั้น RSS, VSZ และ PSS สำหรับแต่ละเธรดจะเหมือนกับเธรดอื่นทั้งหมดในกระบวนการ ใช้ ps หรือด้านบนเพื่อดูข้อมูลนี้ใน linux / unix
มีวิธีมากไปกว่านี้คือการเรียนรู้เพิ่มเติมตรวจสอบการอ้างอิงต่อไปนี้:
ดูเพิ่มเติมที่:
libxml2.so
ไลบรารีที่แชร์จะถูกนับในแต่ละ RSS ดังนั้นผลรวมของ RSS จะมากกว่าหน่วยความจำจริงที่ใช้
top
คำสั่ง ระบบนี้ไม่มีการสลับใด ๆswapon --show
ส่งคืนอะไรเลย คุณอธิบายสิ่งนี้ได้อย่างไร หาก vsz เป็น swap + shared library ในกรณีนี้ shared library มากกว่า 3.3G? เป็นไปได้ไหม? สับสนจริงๆ ...
RSS คือขนาดชุดที่อยู่อาศัย (หน่วยความจำแบบมีอยู่จริง - ขณะนี้อยู่ในพื้นที่หน่วยความจำทางกายภาพของเครื่อง) และ VSZ เป็นขนาดหน่วยความจำเสมือน (พื้นที่ที่จัดสรร - ที่อยู่นี้มีที่อยู่ที่จัดสรรในแผนที่หน่วยความจำของกระบวนการ หน่วยความจำจริงที่อยู่เบื้องหลังมันทั้งหมดในตอนนี้)
โปรดทราบว่าในยุคปัจจุบันของเครื่องเสมือนทั่วไปหน่วยความจำกายภาพจากมุมมองของเครื่องอาจไม่ใช่หน่วยความจำกายภาพจริง
ตัวอย่างที่เรียกใช้น้อยที่สุด
เพื่อให้สมเหตุผลคุณต้องเข้าใจพื้นฐานของการเพจ: เพจจิง x86 ทำงานอย่างไรและโดยเฉพาะอย่างยิ่งที่ระบบปฏิบัติการสามารถจัดสรรหน่วยความจำเสมือนผ่านหน้าตาราง / การเก็บรักษาหนังสือหน่วยความจำภายใน (หน่วยความจำเสมือน VSZ) ก่อนที่จะมีการจัดเก็บข้อมูลสำรองบน RAM หรือดิสก์ (หน่วยความจำถิ่นที่อยู่ RSS)
ทีนี้เพื่อสังเกตสิ่งนี้ในทางปฏิบัติลองสร้างโปรแกรมที่:
mmap
main.c
#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 ต้นน้ำต้นน้ำ
รวบรวมและเรียกใช้:
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
ที่อยู่:
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
: จำเป็นสำหรับ Linux เพื่อให้เราสามารถเรียก mmap ที่มีขนาดใหญ่กว่า RAM จริง: หน่วยความจำสูงสุดที่ malloc สามารถจัดสรรได้เอาท์พุทโปรแกรม:
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
สถานะการออก:
137
ซึ่งตามกฎหมายเลขสัญญาณ 128 +หมายความว่าเราได้รับหมายเลขสัญญาณ9
ซึ่งman 7 signal
บอกว่าเป็นSIGKILLซึ่งถูกส่งโดยนักฆ่าหน่วยความจำออกจากลินุกซ์ออกจากหน่วยความจำนักฆ่า
การตีความผลลัพธ์:
printf '0x%X\n' 0x40009A4 KiB ~= 64GiB
(ps
ค่าเป็น KiB) หลังจาก mmapextra_memory_committed 0
ซึ่งหมายความว่าเรายังไม่ได้แตะหน้าใด ๆ RSS มีขนาดเล็ก1648 KiB
ซึ่งได้รับการจัดสรรสำหรับการเริ่มต้นโปรแกรมปกติเช่น text area, globals เป็นต้น8388608 KiB == 8GiB
มูลค่าของหน้า เป็นผลให้ RSS เพิ่มขึ้น 8GIB เป็นอย่างแน่นอน8390256 KiB == 8388608 KiB + 1648 KiB
ดูเพิ่มเติมที่: /unix/35129/need-explanation-on-resident-set-size-virtual-size
บันทึกนักฆ่า OOM
dmesg
คำสั่งของเราแสดงบันทึกการทำงานของนักฆ่า OOM
การตีความที่ถูกต้องของสิ่งเหล่านั้นถูกถามที่:
บรรทัดแรกของบันทึกคือ:
[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
ดังนั้นเราจึงเห็นว่าน่าสนใจเป็น MongoDB daemon ที่ทำงานในแล็ปท็อปของฉันบนพื้นหลังซึ่งเป็นครั้งแรกที่เรียกใช้ OOM killer โดยสันนิษฐานว่าเมื่อสิ่งที่ไม่ดีพยายามจัดสรรหน่วยความจำบางส่วน
อย่างไรก็ตามนักฆ่า OOM ไม่จำเป็นต้องฆ่าคนที่ตื่นขึ้นมา
หลังจากการร้องขอเคอร์เนลจะพิมพ์ตารางหรือกระบวนการรวมถึง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
และต่อไปข้างหน้าเราจะเห็นว่าmain.out
จริงๆแล้วสิ่งเล็ก ๆ น้อย ๆ ของเราถูกฆ่าตายในการอุทธรณ์ครั้งก่อน:
[ 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
บันทึกนี้กล่าวถึงscore 865
กระบวนการที่มีการสันนิษฐานสูงสุด (ที่เลวร้ายที่สุด) คะแนนฆาตกร OOM เป็นที่กล่าวถึงที่: /unix/153585/how-does-the-oom-killer-decide-which- ขั้นตอนการฆ่าครั้งแรก
สิ่งที่น่าสนใจก็เกิดขึ้นอย่างรวดเร็วก่อนที่จะมีการบันทึกหน่วยความจำที่เป็นอิสระกระบวนการดังกล่าวoom
ถูกปลุกขึ้นอีกครั้งโดยDeadlineMonitor
:
[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
และครั้งนี้ที่ฆ่ากระบวนการ Chromium บางอย่างซึ่งโดยปกติจะเป็นคอมพิวเตอร์หน่วยความจำปกติของฉัน:
[ 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
ทดสอบใน Ubuntu 19.04, Linux kernel 5.0.0
ฉันคิดว่ามากได้รับการพูดเกี่ยวกับ RSS vs VSZ จากมุมมองของผู้ดูแลระบบ / โปรแกรมเมอร์ / ผู้ใช้เมื่อฉันออกแบบ / แอปพลิเคชันรหัสฉันมีความกังวลเกี่ยวกับ RSZ, (หน่วยความจำ Resident) เป็นและเมื่อคุณดึงตัวแปรมากขึ้น (heaped) คุณจะเห็นค่านี้มากขึ้น ลองใช้โปรแกรมอย่างง่ายเพื่อสร้างการจัดสรรพื้นที่ตาม malloc แบบวนซ้ำและตรวจสอบให้แน่ใจว่าคุณกรอกข้อมูลในพื้นที่ malloc'd นั้น RSS ขยับขึ้นเรื่อย ๆ เท่าที่เกี่ยวข้องกับ VSZ มันเป็นมากกว่าการทำแผนที่หน่วยความจำเสมือนที่ linux ทำและหนึ่งในคุณสมบัติหลักของมันมาจากแนวคิดของระบบปฏิบัติการทั่วไป การจัดการ VSZ กระทำโดยการจัดการหน่วยความจำเสมือนของเคอร์เนลสำหรับข้อมูลเพิ่มเติมเกี่ยวกับ VSZ ดูคำอธิบายของ Robert Love ใน mm_struct และ vm_struct ซึ่งเป็นส่วนหนึ่งของโครงสร้างข้อมูลพื้นฐาน task_struct ในเคอร์เนล
พวกเขาไม่ได้จัดการ แต่วัดและอาจมี จำกัด (ดู getrlimit
เรียกระบบเช่นกันบนgetrlimit (2) )
RSS หมายถึงขนาดชุดที่อยู่อาศัย (ส่วนหนึ่งของพื้นที่ที่อยู่เสมือนของคุณนั่งอยู่ใน RAM)
คุณสามารถสอบถามพื้นที่ที่อยู่เสมือนของกระบวนการ 1234 โดยใช้proc (5)ด้วยcat /proc/1234/maps
และสถานะของมัน (รวมถึงการใช้หน่วยความจำ) ถึงcat /proc/1234/status