6.4 ניהול זכרון תרגול
תרגול - ניהול זכרון¶
תרגיל 1 - חקירת buddy allocator¶
הריצו את הפקודה הבאה ובחנו את הפלט:
א. כמה zones יש במערכת שלכם? מהם השמות שלהם?
ב. מה המספר הראשון בכל שורה מייצג? ומה המספר האחרון?
ג. חשבו: אם המספרים בעמודות הגבוהות (8, 9, 10) הם כולם 0, מה זה אומר על מצב הזכרון הפיזי?
תרגיל 2 - חקירת /proc/meminfo¶
הריצו:
א. מצאו את השדות הבאים ורשמו את הערכים שלהם: MemTotal, MemFree, MemAvailable, Cached, SwapTotal, SwapFree.
ב. הסבירו: למה MemAvailable גדול מ-MemFree? מה ההבדל ביניהם?
ג. אם Cached מראה ערך גבוה (למשל כמה GB), האם זה אומר שיש בעיית זכרון? הסבירו.
תרגיל 3 - ניתוח /proc/[pid]/maps¶
כתבו תוכנית C פשוטה שמקצה זכרון עם malloc, ממפה קובץ עם mmap, ואז קוראת ל-getchar() כדי להמתין (שנוכל לבדוק את ה-maps בזמן שהתוכנית רצה):
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
// הקצאה עם malloc
char *heap_mem = malloc(1024 * 1024); // 1MB
// מיפוי אנונימי עם mmap
char *anon_mem = mmap(NULL, 4096 * 10, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
printf("PID: %d\n", getpid());
printf("heap_mem: %p\n", heap_mem);
printf("anon_mem: %p\n", anon_mem);
printf("press enter to exit...\n");
getchar();
free(heap_mem);
munmap(anon_mem, 4096 * 10);
return 0;
}
א. קמפלו והריצו את התוכנית. בטרמינל אחר, הריצו:
מצאו את האזורים שמתאימים ל-heap_mem ול-anon_mem. איך זיהיתם אותם?
ב. מצאו את אזור ה-stack. מה ההרשאות שלו?
ג. מצאו את libc.so ב-maps. כמה VMAs יש לה? מה ההרשאות של כל אחד ולמה?
תרגיל 4 - צפייה ב-Copy-on-Write¶
כתבו תוכנית שמקצה buffer גדול (למשל 100MB), ממלאת אותו בתו כלשהו, ואז קוראת ל-fork.
לפני ואחרי ה-fork, הדפיסו את ה-PID ועצרו עם getchar. בזמן ההמתנה, השוו את /proc/<PID>/maps של האב והבן.
אחר כך, בתהליך הבן, שנו בית אחד ב-buffer ושוב עצרו. בדקו שוב את ה-maps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
size_t size = 100 * 1024 * 1024; // 100MB
char *buf = malloc(size);
memset(buf, 'A', size);
printf("parent PID: %d, press enter to fork...\n", getpid());
getchar();
pid_t pid = fork();
if (pid == 0) {
// תהליך הבן
printf("child PID: %d, press enter to modify memory...\n", getpid());
getchar();
// שינוי בית אחד - מפעיל COW
buf[0] = 'B';
printf("child modified memory, press enter to exit...\n");
getchar();
_exit(0);
}
// תהליך האב
printf("parent waiting for child...\n");
wait(NULL);
free(buf);
return 0;
}
בכל שלב, בדקו את /proc/<PID>/smaps או /proc/<PID>/status ומצאו את השדה RssAnon. מה משתנה אחרי שהבן כותב לזכרון?
תרגיל 5 - שאלה תיאורטית¶
הסבירו את הזרימה המלאה של מה שקורה כשתהליך ניגש לכתובת וירטואלית שהוקצתה עם mmap אנונימי, בפעם הראשונה.
ציינו את כל השלבים: מהרגע שהCPU מנסה לגשת לכתובת, דרך ה-page fault, חיפוש VMA, הקצאת דף פיזי, עדכון page table, ועד שהפקודה רצה שוב בהצלחה.
מה ההבדל אם הכתובת הייתה של קובץ ממופה (file-backed mmap) במקום מיפוי אנונימי?