מה זה זיכרון וירטואלי - האשליה החכמה שעליה בנוי כל מחשב מודרני¶
כשתוכנית שלכם "קוראת מכתובת זיכרון 0x1000", היא לא באמת נוגעת בשבב הזיכרון הפיזי בכתובת ההיא. היא נוגעת בשקר מתוחכם ומדויק להפליא, שקר שכל מערכת הפעלה מודרנית משתמשת בו כדי לגרום למחשבים לעבוד בכלל. השקר הזה נקרא זיכרון וירטואלי, וברגע שמבינים אותו, מבינים חצי מהדברים המסתוריים שקורים בתוך מחשב.
האנלוגיה שתפתור לכם את זה¶
תדמיינו בניין דירות ענק, ובו אלף דיירים. לכל דייר אומרים שהוא גר ב"דירה 1". כולם. כל אלף הדיירים בטוחים שהם גרים בדירה מספר 1, ואף אחד לא מתלונן, כי אף אחד לא באמת יודע שלכל האחרים אומרים בדיוק אותו דבר.
איך זה עובד בלי כאוס מוחלט? יש מנהל בניין עם ספר כתובות סודי, שמתרגם בין "דירה 1 של דייר X" לבין הדירה הפיזית האמיתית שבה הוא גר, איפשהו בבניין. כל דייר חושב שיש לו את "דירה 1" הפרטית שלו, בזמן שבפועל כולם חולקים את אותו בניין פיזי, פשוט בדירות אמיתיות שונות.
זו בדיוק ההגדרה של זיכרון וירטואלי. כל תהליך במחשב "חושב" שיש לו מרחב כתובות פרטי ורציף לגמרי לעצמו, מכתובת 0 ועד הסוף. בפועל, כל התהליכים חולקים את אותו זיכרון פיזי (RAM), בדיוק כמו שכל הדיירים חולקים את אותו בניין.
מי מתרגם בין הכתובות בפועל¶
מנהל הבניין, במקרה של המחשב, הוא רכיב חומרה שנקרא MMU, memory management unit. בכל פעם שתוכנית ניגשת לכתובת זיכרון וירטואלית, ה-MMU מתרגם אותה לכתובת פיזית אמיתית ב-RAM, על סמך מבנה נתונים שמערכת ההפעלה מתחזקת בשם טבלת עמודים, page table. כל תהליך מקבל טבלת עמודים משלו, בדיוק כמו שלכל דייר יש רשומה נפרדת בספר הכתובות של מנהל הבניין.
התרגום הזה קורה בכל גישה לזיכרון, מיליוני פעמים בשנייה, וברוב המכריע של המקרים החומרה מבצעת אותו כל כך מהר שהתוכנית בכלל לא "מרגישה" שיש שם שכבת תרגום.
מה זה נותן לנו בפועל - בידוד תהליכים¶
היתרון הראשון והכי חשוב הוא בידוד. אם תוכנית שברירית מנסה לגשת ל"כתובת 0x1000" שלה, היא לעולם לא יכולה בטעות לגעת בזיכרון האמיתי של תוכנית אחרת, גם אם לתוכנית האחרת יש בדיוק אותה כתובת וירטואלית. כל תהליך חי בעולם הפרטי שלו, וקריסה של תוכנית אחת לא יכולה, ברמה הרגילה, לפגוע בזיכרון של תוכנית אחרת - בדיוק כמו שדייר שהורס את "דירה 1" שלו לא הורס בטעות את הדירה של השכן, למרות שלשניהם יש דירה עם אותו מספר.
התרגיל שגורם לזיכרון "להיראות" יותר גדול - swapping¶
היתרון השני הוא היכולת לתת לתהליך אשליה של יותר זיכרון ממה שבאמת קיים פיזית במחשב. כשה-RAM מתמלא, מערכת ההפעלה יכולה "לפנות" חלקים מהזיכרון שלא נעשה בהם שימוש לאחרונה, ולהעביר אותם זמנית לדיסק - תהליך שנקרא swapping, או paging out. כשמישהו צריך את הזיכרון הזה שוב, המערכת מביאה אותו בחזרה מהדיסק. זה איטי בהרבה מגישה ל-RAM, אבל זה מאפשר להריץ יותר תהליכים ממה שהזיכרון הפיזי לבד היה מאפשר.
אחד הטריקים החכמים ביותר - copy-on-write¶
הנה משהו יפה במיוחד. כשתהליך יוצר תהליך בן חדש (fork), לכאורה הוא צריך להעתיק את כל הזיכרון שלו לתהליך החדש - מבזבז זמן וזיכרון בטירוף. במקום זה, מערכות הפעלה מודרניות עושות טריק - שני התהליכים ממשיכים להצביע על אותו זיכרון פיזי בדיוק, ורק כשאחד מהם באמת מנסה לשנות, לכתוב על, חלק מהזיכרון, המערכת מעתיקה בדיוק את החלק הזה ברגע האחרון. הטכניקה הזו נקראת copy-on-write, והיא אפשרית בדיוק בזכות שכבת התרגום של הזיכרון הווירטואלי, שמאפשרת למערכת "לשקר" לשני התהליכים בו זמנית.
כל הרעיונות האלה - MMU, טבלאות עמודים, swapping, ו-copy-on-write - הם בדיוק הדברים שנכנסים לעומק אמיתי בקורס ליבת המחשב, כשמגיעים לחלק של אסמבלי 32 סיביות ו-paging.
לסיכום¶
זיכרון וירטואלי הוא אחת ההמצאות החכמות ביותר בעולם מערכות ההפעלה - אשליה מתוחכמת שגורמת לכל תהליך להרגיש שיש לו בניין שלם לעצמו, בזמן שבפועל כולם חולקים את אותו RAM פיזי, מתורגם ומתוזמן בקפידה על ידי החומרה ומערכת ההפעלה יחד. ברגע שמבינים את הטריק הזה, גם בידוד תהליכים, גם swapping, וגם copy-on-write, פתאום הופכים מקסם למכניקה פשוטה והגיונית.
בואו תמשיכו את הלמידה עם קהילה שכבר שם.