280 likes | 418 Views
מערכות הפעלה. תרגול 13 – ניהול זיכרון ב- Linux : המשך. תוכן התרגול. טבלת המסגרות מטמון הדפים למה יש בו צורך? איך דפים מגיעים למטמון? שדות ומבנים במטמון הדפים דוגמה פינוי דפים דירוג פעילות של דפים בזיכרון פינוי בפועל של זיכרון פינוי דפים ממרחבי זיכרון. מטמון הדפים – למה יש בו צורך?.
E N D
מערכות הפעלה תרגול 13 – ניהול זיכרון ב-Linux : המשך
תוכן התרגול • טבלת המסגרות • מטמון הדפים • למה יש בו צורך? • איך דפים מגיעים למטמון? • שדות ומבנים במטמון הדפים • דוגמה • פינוי דפים • דירוג פעילות של דפים בזיכרון • פינוי בפועל של זיכרון • פינוי דפים ממרחבי זיכרון תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים – למה יש בו צורך? • נסתכל על המצב האפשרי הבא: • דף,השייך למרחב הזיכרון של תהליך מסוים, מפונה. • לפני שהפינוי הסתיים, התהליך מנסה לגשת לאותו דף. • מתי נסמן שהדף לא בזיכרון? (present = 0 בטבלת הדפים) • אם לפני הפינוי בפועל, ואז • כשמחליטים לפנות דף קודם כל מסמנים אותו ע“י present = 0. • התהליך מנסה לגשת לדף, מגלה ש- present = 0, ניגש לזיכרון המשני לפי הכתובת במאגר הדפדוף. • המערכת עוד לא הספיקה לכתוב את הדף למאגר הדפדוף => • הדף שנקרא ע“י התהליך לא נכון (נתונים לא מעודכנים ואף יתכן זבל) • אם אחרי הפינוי בפועל, ואז • מתחילים לפנות את הדף. • התהליך ניגש לדף , ה-present = 1 עדיין. • הדף פונה ודף אחר נטען לאותה מסגרת • התהליך ניגש למסגרת המצוינת בטבלת הדפים =>גישה לא חוקית ! תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים • נדרש מנגנון שינהל את פינוי והבאת הדפים מ/לזיכרון הראשי! • מטמון הדפים (Page Cache) הוא המנגנון המרכזי לטעינת ופינוי דפים בין הזיכרון לדיסק ב-Linux. • כל דף של מרחב הזיכרון של תהליך מפונה תמיד דרך מטמון הדפים. • מטמון הדפים ממומש כחלק מטבלת המסגרות. תרגול 13 – ניהול זיכרון ב-Linux : המשך
טבלת המסגרות ב-Linux (1) • גרעין Linux מחזיק מערך עם כניסה לכל מסגרת בזיכרון הראשי של המחשב • המערך נקרא mem_map וכל כניסה היא מסוג struct page • קובץ גרעין include/linux/mm.h • מספר שדות חשובים בכל כניסה: • count – מונה שימוש (reference counter) של הדף שבמסגרת: כמה מרחבי זיכרון מצביעים לדף זה כשהוא בזיכרון. אם ערך המונה הוא 0, המסגרת פנויה • flags – דגלים המתארים את מצב הדף שבמסגרת, כגון: • PG_locked – מציין שהמסגרת נעולה עקב פעולת פינוי/הבאת דף שעדיין לא הסתיימה • PG_dirty – מציין שתוכן המסגרת "מלוכלך" • דגלים נוספים שנראה בהמשך: PG_referenced, PG_active, PG_lru – משמשים למנגנון פינוי הדפים. תרגול 13 – ניהול זיכרון ב-Linux : המשך
טבלת המסגרות ב-Linux (2) • mapping - מצביע לאובייקט ניהול המכיל מידע ופונקציות לטיפול בדף שבמסגרת (פינוי וטעינה) לפי סוג המיפוי שלו (ממופה לקובץ, או ממופה אנונימי) • index - מציין את המיקום הפיזי של הדף במאגר בדיסק • עבור מידע מקובץ, את ההיסט מתחילת הקובץ (offset) • עבור דף מזיכרון תהליך, את מזהה המגירה • שדות נוספים שנראה בהמשך:lru, next_hash, pprev_hash תרגול 13 – ניהול זיכרון ב-Linux : המשך
טבלת המסגרות flags: R - PG_referenced D - PG_dirty A - PG_active L - PG_lru מטמון הדפדוף מסגרת גרעין אוביקט ניהול קובץ דיסקים מאגר דפדוף swap1 מאגר דפדוף swap2 קובץ /bin/ls קובץ /home/eli/file1 תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים – hash table • מטמון הדפים מכיל hash table המתרגם צירוף של (mapping+index) לכתובת מסגרת (אם יש כזו) המכילה את הדף במיקום index של האובייקט mapping. • כל המסגרות שמתאימות לאותו hash מקושרות ברשימה כפולה מעגלית דרך השדות next_hash ו-pprev_hash ברשומת המסגרת. • ל-hash table יש תפקיד מרכזי במנגנון הדפדוף, כפי שנראה בהמשך • הפונקציות/מאקרו הבאות, המוגדרות בקבצי הגרעין mm/filemap.c ו-include/linux/pagemap.h, קשורות ל-hash table: • page_hash() – פונקצית ה-hash • find_get_page() – מקבלת mapping+index ומחזירה מצביע למסגרת המכילה את הדף המתאים (או NULL אם אין) • add_to_page_cache() – הוספת מסגרת + מיקום בדיסק (במגירה או בקובץ) למטמון וכך גם ל-hash-table תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים – מוני שימוש • בדומה למסגרת, לכל מגירה במאגר הדפדוף יש מונה שימוש בשם swap_map, הסופר כמה מרחבי זכרון מצביעים לדף המאוחסן במגירה. • מבחינת מונה השימוש של מסגרת (שדה count) או מגירה (swap_map), מטמון הדפים נחשב כמרחב זיכרון נפרד המשתמש בדף המאוחסן בה • כאשר מסגרת או מגירה הם בשימוש מטמון הדפים, מוגדל המונה ב-1. הקטנת המונה ב-1 מבוצעת עם ניתוק המסגרת או המגירה מהמטמון • המטרה: למנוע שיבוש במיפוי ה-hash-table באמצעות הקצאה מחדש של המסגרת/מגירה עד להוצאת הדף מהמטמון תרגול 13 – ניהול זיכרון ב-Linux : המשך
הקשר בין מסגרת למגירה • הקשר בין מסגרת ומגירה, המכילות את אותו דף ממופה אנונימי, הינו דינמי: • דף המצוי במגירה יכול להיטען לכל מסגרת פנויה שתוקצה בעת הצורך • דף מפונה למגירה בדיסק (והמסגרת מתפנה) רק לאחר שכל מרחבי הזיכרון השותפים בו מצביעים על המגירה בדיסק – והקשר הקיים בין המסגרת למגירה ניתן לניתוק • Linux מאפשרת קישור דינמי גם בכיוון ההפוך: • לאחר שדף נטען לזיכרון וכל מרחבי הזיכרון מצביעים למסגרת, הגרעין בוחר במקרים מסוימים לשחרר את המגירה ולנתק את הקשר הקיים • לפני שכותבים דף לדיסק, מקצים לו מגירה חדשה אם אין לו • מטמון הדפים מחזיק את הקשר בין המגירה והמסגרת של אותו דף ממופה אנונימי, כל עוד קשר זה מתקיים (ומסמן בכך את קיום הקשר) • כאשר הקשר ניתק, המסגרת מוצאת ממטמון הדפים • ..וגם המגירה (מונה השיתוף של המגירה מוקטן) תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים – שלבי פינוי דף • מטמון הדפים מצביע למסגרת בזיכרון הראשי, בתוכה נמצא הדף (ה-count של המסגרת מוגדל ב- 1) • מוקצית מגירה במאגר הדפדוף, אליה יעבור הדף המפונה • המטמון מצביע גם למגירה זו • הדף נכתב למגירה במאגר הדפדוף. • באופן סימטרי מבוצעת גם הבאת דף ממאגר הדפדוף לזיכרון הראשי. תרגול 13 – ניהול זיכרון ב-Linux : המשך
1 P זיכרון ראשי 2 S1 PC S2 מאגר דפדוף מטמון הדפים – דוגמה(1) • הרלוונטיות של מטמון הדפים גדלה עוד יותר כאשר קיים שיתוף של דף ע“י מספר תהליכים. • להלן דוגמה לתהליך פינוי דף ממופה אנונימי למסגרת • S1 ו-S2 הם שני מרחבי זיכרון שלהם דף משותף P, המצוי בתחילה במסגרת בזיכרון. מונה השיתוף (count) מטמון הדפים תרגול 13 – ניהול זיכרון ב-Linux : המשך
2 P זיכרון ראשי 2 S1 PC S2 P 2 מאגר דפדוף מטמון הדפים – דוגמה(2) • במסגרת פינוי דפים, מבוצע מעבר על הטבלאות של S1 והגרעין מחליט לפנות את P לדיסק: • הדף P אינו במטמון הדפים (שדה mapping במסגרת מצביע על NULL) ולכן: • מוקצית מגירה עבור P • המסגרת והמגירה של P מקושרות למטמון הדפים (עדכון מוני השיתוף, עדכון mapping ו-index במסגרת) • הטבלה ב-S1 עוברת להצביע על המגירה של P (מזהה המגירה מוצב בטבלה, עדכון מוני השיתוף) • P עדיין לא מפונה פיזית מהזיכרון! מונה השיתוף (swap_map) תרגול 13 – ניהול זיכרון ב-Linux : המשך
3 P זיכרון ראשי 1 S1 PC S2 P 3 מאגר דפדוף מטמון הדפים – דוגמה(3) • בהמשך, מבוצע מעבר גם על הטבלאות של S2 ושוב הגרעין מחליט לפנות את P לדיסק: • כעת, הדף P כבר במטמון הדפים ולכן: • הטבלה ב-S2 עוברת להצביע על המגירה של P (ומעדכנים מוני שיתוף) • P עדיין לא מפונה פיזית מהזיכרון! תרגול 13 – ניהול זיכרון ב-Linux : המשך
4 זיכרון ראשי S1 PC S2 P 2 מאגר דפדוף מטמון הדפים – דוגמה(4) • מאוחר יותר, מתבצע פינוי פיזי של הדף P, לאחר שהמסגרת כבר לא משמשת מרחבי זיכרון של תהליכים: • תוכן המסגרת נכתב לדיסק • המסגרת מוצאת ממטמון הדפים ומסומנת כפנויה (עדכון mapping, מונה השיתוף) • המגירה מוצאת אף היא ממטמון הדפים (עדכון מונה השיתוף) תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים – סיכום דוגמה • ראינו בדוגמה זו כיצד מאפשר מטמון הדפים פעולה הדרגתית של פינוי דף, ממרחב זיכרון אחד בכל פעם, תוך שמירה על תיאום בין מרחבי הזיכרון המשתמשים בדף. • אין צורך לעדכן את כל טבלאות הדפים המתייחסות לאותו דף בבת אחת • ניתן לדחות את פעולת הפינוי הפיזי ככל הרצוי • אם בשלב כלשהו תהליך ניגש לדף, שמבחינתו נמצא בזיכרון המשני, אך בפועל נמצא עדיין בזיכרון הראשי: • לא יהיה צורך להביא את הדף מהזיכרון המשני • התהליך יקבל את מספר המסגרת תוך שימוש ב-hash של מטמון הדפים (ע"י שימוש בפונקציה find_get_page()) • מצב זה נקרא Minor Page Fault. (אפשרי בשלבים 2,3 בדוגמה) • הדף מפונה פיזית פעם אחת, ולמקום אחד בדיסק תרגול 13 – ניהול זיכרון ב-Linux : המשך
מטמון הדפים – טעינת דף • בטעינת דף מתבצעות הפעולות בסדר הפוך בקירוב, תוך שימוש במטמון הדפים • בטעינת דף למרחב זיכרון מסוים, בודקים אם הדף כבר נטען למסגרת בזיכרון באמצעות find_get_page(): • אם כן, רק מעדכנים את טבלת הדפים ומוני השיתוף • אחרת, טוענים את הדף לזיכרון ומכניסים אותו למטמון הדפים • גם טעינת דף משותף מתבצעת בצורה הדרגתית תוך שמירה על תיאום בין התהליכים • הדף נטען פעם אחת בלבד ולמסגרת אחת בלבד תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי דפים ב-Linux • פינוי דפים מהזיכרון לדיסק הינו מנגנון בעל שלושה מרכיבים: • דירוג דינמי של רמת הפעילות של כל דף במסגרת בזיכרון (שאינו שייך לגרעין) כאשר עולה הצורך בפינוי בפועל של זיכרון: • מעבר על רשימת המסגרות בעלות ה"פעילות הנמוכה ביותר" ופינוי בפועל של המסגרות שאינן בשימוש מרחבי זיכרון של תהליכים אם הגרעין מעריך שצריך לפנות דפים נוספים: • מעבר על טבלאות הדפים של כל מרחבי הזיכרון של תהליכי משתמש: כאשר מאותרת כניסה השייכת לאזור זיכרון ומצביעה למסגרת הניתנת לפינוי ובעלת פעילות "נמוכה", מבוצע פינוי של הדף ממרחב הזיכרון הנבדק • פינוי דף ממרחב זיכרון יחיד, בהתאם לשיטה שהודגמה קודם תרגול 13 – ניהול זיכרון ב-Linux : המשך
דירוג פעילות של דפים בזיכרון (1) • הגרעין מחזיק שתי רשימות מקושרות כפולות מעגליות של רשומות מסגרות במטמון הדפים: • active_list – רשימת מסגרות הדפים ה"פעילים", כלומר דפים שניגשו אליהם "לאחרונה" • inactive_list – רשימת מסגרות הדפים ה"לא-פעילים", כלומר דפים שלא ניגשו אליהם "זמן מה" • active_list, inactive_list הם שמות המשתנים הגלובליים המצביעים לראשי הרשימות, המוגדרים בקובץ הגרעין mm/page_alloc.c • הרשימות לא-חופפות, ורשומת כל מסגרת הניתנת לפינוי מקושרת לאחת הרשימות • מסגרות (הרשומות שלהן) מועברות בין הרשימות כפי שנראה בהמשך • מסגרת מוספת לרשימה דרך ראש הרשימה תרגול 13 – ניהול זיכרון ב-Linux : המשך
דירוג פעילות של דפים בזיכרון (2) • הדגל PG_lru דולק ברשומת מסגרת הנמצאת באחת מהרשימות (לא מסגרת השייכת לגרעין, למשל) • הקישור של מסגרת לאחת הרשימות הוא באמצעות השדה lru ברשומת המסגרת • הדגל PG_active דולק רק בכל רשומת מסגרת השייכת לרשימה active_list • הדגל PG_referenced ברשומת מסגרת מציין שבוצעה גישה לדף במסגרת זו. • דגל זה משמש ליצירת שתי הזדמנויות למסגרת להישאר ב-active_list אבל גם שתי מדרגות למסגרת על-מנת להיכנס ל-active_list מתוך ה-inactive_list. תרגול 13 – ניהול זיכרון ב-Linux : המשך
דירוג פעילות של דפים בזיכרון (3) • הפונקציה mark_page_accessed(), מופעלת לציון גישה למסגרת • מבצעת כדלקמן: אם המסגרת ב-active_list או PG_referenced כבוי, מדליקה את PG_referenced. אחרת, מכבה את PG_referenced ומכניסה את המסגרת מחדש ל-active_list • קובץ גרעין mm/filemap.c • הפונקציה refill_inactive(), המופעלת רק במקרה שיש צורך לפנות דפים , מעדכנת את inactive_list • עוברת על כל המסגרות ב-active_list מסוף הרשימה (מסגרות ותיקות ביותר): אם PG_referenced דלוק, מכבה אותו ומכניסה את המסגרת מחדש ל-active_list. אחרת, מעבירה את המסגרת ל-inactive_list עם דגל PG_referenced דולק • קובץ גרעין mm/vmscan.c תרגול 13 – ניהול זיכרון ב-Linux : המשך
דירוג פעילות של דפים בזיכרון (4) PG_referenced=0 PG_active=1 add_to_page_cache() PG_referenced=0 PG_active=0 • פינוי בפועל של דפים ממסגרות מבוצע החל מסוף רשימת ה- inactive_list • המסגרות הכי "לא פעילות" • הפונקציה mark_page_accessed() מופעלת עבור דף כלשהו במקרים הבאים: • בכל פעם שהדף נטען מהדיסק • בכל פעם שהגרעין סורק את טבלאות הדפים כדי לפנות דפים ומגלה שביט accessed של הדף בטבלת הדפים דלוק (אז גם הביט accessed מכובה) • הפונקציה refill_inactive() מופעלת כאשר יש צורך לפנות דפים, כפי שנראה בהמשך • האלגוריתם המתקבל הוא קירוב ל-LFU: 3 הזדמנויות + ניהול מחסנית refill_inactive() mark_page_accessed() PG_referenced=1 PG_active=1 PG_referenced=1 PG_active=0 תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי בפועל של זיכרון (1) • כפי שכבר הוזכר קודם, פינוי בפועל של מסגרות ב-Linux מתבצע כפעולה של חוסר ברירה • Linux נוטה לנצל את הזיכרון הראשי ככל האפשר מבלי לפנות דפים כלל • מוגדר סף "קריטיות" threshold)) של כמות מינימלית של מסגרות שחייבת להישאר פנויה. • הסיבות להגדרת הסף: • לצורך הפעלת אלגוריתמים של פינוי זיכרון ישנו צורך במספר מסגרות פנויות. • כמו כן, זה מקטין את זמן הטיפול ב-page fault שמצריך טעינת דף מהזיכרון המשני, כי אין צורך לפנות מסגרת, אלא רק לטעון דף למסגרת פנויה. • מוגדר גם סף עליון, שמעבר לו אין צורך לבצע פינוי מסגרות. • פונקצית הפינוי תמיד תנסה להגיע לסף העליון כדי למנוע סחרור – thrashing. תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי בפועל של זיכרון (2) • מנגנון הפינוי, הקרוי מנגנון מחזור מסגרות (Page Frame Reclaiming), מופעל בקריאה לפונקציה try_to_free_pages() • כל פונקציות פינוי המסגרות מוגדרות בקובץ הגרעין mm/vmscan.c • הפעלת הפונקציה try_to_free_pages() מבוצעת במקרים הבאים: • במקרה שחוט גרעין מיוחד, הקרוי kswapd, מגלה שכמות המסגרות הפנויות קטנה/שווה לסף הנמוך. • מאפשר לנצל זמן עם פעילות תהליכים נמוכה לפעולות פינוי הזיכרון, מה שמשפר את ביצועי המערכת. • כאשר הקצאת מסגרת חדשה נכשלת (בעקבות הגעה לסף הקריטי) מתבצעת הפעלה ישירה של הפונקציה או שמעירים את kswapd • הפונקציה try_to_free_pages() מנסה לפנות SWAP_CLUSTER_MAX (32) מסגרות בזיכרון. תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי בפועל של זיכרון (3) • הטקטיקה לשחרור מסגרות היא כדלקמן: • מבוצעות מספר איטרציות של ניסיונות שחרור מסגרות • בכל איטרציה: • מנסים לשחרר מסגרות ע"י קריאה לפונקציות לצמצום מטמונים שונים (פרט למטמון הדפים) • קוראים ל-refill_inactive() על-מנת להגדיל את ה-inactive_list • מבצעים סריקה של ה-inactive_list מהסוף (קריאה ל-shrink_cache()) ובה: • משחררים מסגרות הנמצאות בשימוש מטמון הדפים בלבד (mapping != NULL, count == 1) • מסגרת המכילה דף מלוכלך, כלומר שעבר עדכון (דגל PG_dirty דולק), נכתבת לדיסק לפני פינויה. תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי דפים ממרחבי זיכרון (1) • אם במהלך סריקת המסגרות ב-inactive_list נספרות "יותר מדי" (מעבר לסף מוגדר) מסגרות המסומנות בשימוש ע"י תהליכים (count > 1) ו/או שאינן במטמון הדפים (mapping == NULL), מופסקת הסריקה ומופעלת הפונקציה swap_out() לפינוי דפים ממרחבי זיכרון. • הפונקציה swap_out() מנסה לפנות דפים ממרחבי זיכרון הטעונים למסגרות. • המטרה: להביא את המסגרות למצב פנוי (count == 0) או שהן בשימוש מטמון הדפים בלבד (count == 1, mapping != NULL) – מסגרות "לפני שחרור" • הפונקציה מסיימת אם היא מצליחה להביא SWAP_CLUSTER_MAX מסגרות למצב הרצוי או אם היא סרקה מתארי זיכרון בכמות שהייתה כשהתחילה לרוץ. תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי דפים ממרחבי זיכרון (2) • פעולת הפונקציהswap_out() היא לסרוק את כל טבלאות הדפים הממפות את כל אזורי הזיכרון בכל מרחבי הזיכרון במערכת (עד לכמות הנסרקת), ולכל כניסה המצביעה למסגרת בזיכרון, מבוצעות הפעולות הבאות (המוגדרות בפונקציה try_to_swap_out()): • אם הביט accessed בכניסה בטבלה דלוק, קוראת ל-mark_page_accessed() עבור המסגרת, מכבה את הביט ועוברת למסגרת הבאה. • הדף במסגרת ניתן לפינוי אם מתקיימים כל התנאים הבאים: • אזור הזיכרון המכיל את הדף ניתן לפינוי (דגל VM_LOCKED במתאר אזור הזיכרון כבוי) • המסגרת לא ב-active_list (דגל PG_active כבוי) תרגול 13 – ניהול זיכרון ב-Linux : המשך
פינוי דפים ממרחבי זיכרון (3) • אם הדף ניתן לפינוי, מתבצע כדלקמן: • אם הדגל dirty בכניסה בטבלת הדפים דלוק, מודלק דגל PG_dirty ברשומת המסגרת לציון דף "מלוכלך" (מעודכן) שיש לכתבו לדיסק לפני פינויו • מבוצע פינוי של הדף ממרחב הזיכרון תוך שימוש במטמון הדפים (כפי שהוסבר קודם): • אם הדף "מלוכלך" (PG_dirty דלוק), הדף צריך להתפנות לדיסק: • אם הדף לא במטמון הדפים, הוא מוכנס למטמון הדפים: הקצאת מגירה אם ממופה אנונימי, עדכון mapping, index • עדכון מוני שיתוף במסגרת ו(אם צריך) במגירה • עדכון הכניסה בטבלת הדפים: מזהה מגירה למיפוי אנונימי, NULL למיפוי לקובץ • דף מיפוי אנונימי "קר" לא עודכן מעולם (PG_dirty כבוי) ולכן מכיל אפסים בלבד. עבור דף כזה, מוכנס NULL לכניסה בטבלת הדפים. כשדף זה יידרש שוב, יוחזר דף עם אפסים. תרגול 13 – ניהול זיכרון ב-Linux : המשך