ערימת זיכרון ושטח ערימה בג'אווה

1. הקדמה

כדי להריץ יישום בצורה אופטימלית, JVM מחלק את הזיכרון לזיכרון ערימה וערימה. בכל פעם שאנחנו מכריזים על משתנים ואובייקטים חדשים, התקשרו לשיטה חדשה, הכריזו על חוּט או לבצע פעולות דומות, JVM מייעד זיכרון לפעולות אלה מ- Stack Memory או Heap Space.

במדריך זה נדון במודלי זיכרון אלה. אנו נגייס כמה הבדלים מרכזיים ביניהם, כיצד הם מאוחסנים ב- RAM, התכונות שהם מציעים ואיפה להשתמש בהם.

2. ערימת זיכרון בג'אווה

Stack Memory ב- Java משמש להקצאת זיכרון סטטי ולביצוע של שרשור. הוא מכיל ערכים פרימיטיביים הספציפיים לשיטה והפניות לאובייקטים הנמצאים בערמה, המופנים מהשיטה.

הגישה לזיכרון זה היא בסדר Last-in-First-Out (LIFO). בכל פעם שקוראים לשיטה חדשה, נוצר בלוק חדש על גבי הערימה המכיל ערכים ספציפיים לאותה שיטה, כמו משתנים פרימיטיביים והפניות לאובייקטים.

כאשר השיטה מסיימת את הביצוע, מסגרת הערימה המתאימה שלה נשטפת, הזרימה חוזרת לשיטת הקריאה והמקום זמין לשיטה הבאה.

2.1. תכונות עיקריות של זיכרון ערימה

מלבד מה שדנו בו עד כה, להלן כמה תכונות אחרות של זיכרון הערימה:

  • הוא גדל ומתכווץ כששיטות חדשות נקראות ומחזירות בהתאמה
  • משתנים בתוך הערימה קיימים רק כל עוד השיטה שיצרה אותם פועלת
  • זה מוקצה אוטומטית ומוקצה כאשר השיטה מסיימת את הביצוע
  • אם זיכרון זה מלא, ג'אווה זורקת java.lang.StackOverFlowError
  • הגישה לזיכרון זה מהירה בהשוואה לזיכרון ערימה
  • זיכרון זה הוא threadsafe כיוון שכל thread פועל בערימה משלו

3. גיבוב שטח בג'אווה

שטח ערימה בג'אווה משמש להקצאת זיכרון דינמי לאובייקטים של ג'אווה ושיעורי JRE בזמן הריצה. אובייקטים חדשים נוצרים תמיד במרחב הערימה וההפניות לאובייקטים אלה נשמרות בזיכרון הערימה.

לאובייקטים אלה יש גישה גלובלית וניתן לגשת אליהם מכל מקום ביישום.

מודל זיכרון זה נשבר עוד יותר לחלקים קטנים יותר הנקראים דורות, אלה הם:

  1. דור צעיר - זה המקום שבו כל האובייקטים החדשים מוקצים ומתיישנים. איסוף זבל מינורי מתרחש כאשר הדבר מתמלא
  2. דור ישן או קבוע - כאן מאוחסנים חפצים ששרדו זמן רב. כאשר מאוחסנים אובייקטים בדור הצעיר, נקבע סף לגיל האובייקט וכאשר מגיעים לסף זה, האובייקט מועבר לדור הישן
  3. דור קבוע - זה מורכב ממטא נתונים של JVM עבור שיעורי זמן הריצה ושיטות היישום

חלקים שונים אלה נדונים גם במאמר זה - ההבדל בין JVM, JRE ו- JDK.

אנחנו תמיד יכולים לתפעל את גודל זיכרון הערימה בהתאם לדרישה שלנו. למידע נוסף, בקרו במאמר מקושר זה של באלדונג.

3.1. תכונות עיקריות של זיכרון Java Heap

מלבד מה שדנו עד כה, להלן כמה מאפיינים אחרים של שטח ערימה:

  • ניתן לגשת אליו באמצעות טכניקות מורכבות לניהול זיכרון הכוללות דור צעיר, דור ישן או קבוע, ודור קבוע
  • אם שטח הערימה מלא, ג'אווה זורקת java.lang.OutOfMemoryError
  • הגישה לזיכרון זה יחסית איטית יותר מזיכרון הערימה
  • בניגוד לערימה, זיכרון זה אינו מוקצה אוטומטית. הוא זקוק לאוסף זבל כדי לפנות חפצים שאינם בשימוש כדי לשמור על יעילות השימוש בזיכרון
  • שלא כמו מחסנית, ערימה אינה בטיחות אשכולות ויש צורך לשמור עליה על ידי סנכרון נכון של הקוד

4. דוגמא

בהתבסס על מה שלמדנו עד כה, בואו ננתח קוד Java פשוט ונבחן כיצד מתנהל כאן זיכרון:

אדם בכיתה {int id; שם מחרוזת; אדם ציבורי (מזהה int, שם מחרוזת) {this.id = id; this.name = שם; }} מחלקה ציבורית PersonBuilder {אדם סטטי פרטי buildPerson (מזהה int, שם מחרוזת) {Return person חדש (id, name); } ראשי ריק סטטי ציבורי (String [] args) {int id = 23; שם מחרוזת = "ג'ון"; אדם אדם = אפס; אדם = buildPerson (מזהה, שם); }}

בואו ננתח את זה צעד אחר צעד:

  1. עם הכניסה ל רָאשִׁי() שיטה, ייווצר מקום בזיכרון הערימה לאחסון פרימיטיבים והפניות לשיטה זו
    • הערך הפרימיטיבי של המספר השלם תְעוּדַת זֶהוּת יאוחסן ישירות בזיכרון הערימה
    • משתנה הייחוס אדם מהסוג אדם ייווצר גם בזיכרון הערימה אשר יצביע על האובייקט הממשי בערימה
  2. הקריאה לבנאי הפרמטרי אדם (int, מחרוזת) מ רָאשִׁי() יקצה זיכרון נוסף על גבי הערימה הקודמת. זה יאחסן:
    • ה זֶה הפניה לאובייקט של האובייקט הקורא בזיכרון הערימה
    • הערך הפרימיטיבי תְעוּדַת זֶהוּת בזיכרון הערימה
    • משתנה הייחוס של חוּט טַעֲנָה שֵׁם אשר יצביע על המחרוזת בפועל מתוך מאגר המיתרים בזיכרון הערימה
  3. ה רָאשִׁי השיטה קוראת עוד יותר ל buildPerson () שיטה סטטית, אשר הקצאה נוספת שלה תתבצע בזיכרון הערימה על גבי הקודמת. פעולה זו תאחסן שוב משתנים באופן שתואר לעיל.
  4. עם זאת, עבור האובייקט החדש שנוצר אדם מהסוג אדם, כל משתני המופעים יאוחסנו בזיכרון הערימה.

הקצאה זו מוסברת בתרשים זה:

5. סיכום

לפני שנסיים מאמר זה, נסכם במהירות את ההבדלים בין זיכרון הערימה לבין שטח הערימה:

פָּרָמֶטֶרזיכרון ערימהערימת שטח
יישוםנעשה שימוש בערימה בחלקים, אחד בכל פעם במהלך ביצוע הברגההיישום כולו משתמש בשטח ערימה בזמן ריצה
גודלל- Stack יש מגבלות גודל בהתאם למערכת ההפעלה והיא בדרך כלל קטנה יותר מ- Heapאין הגבלת גודל ב- Heap
אִחסוּןמאחסן רק משתנים פרימיטיביים והפניות לאובייקטים שנוצרים ב- Heap Spaceכל האובייקטים שזה עתה נוצרו מאוחסנים כאן
להזמיןניתן לגשת אליו באמצעות מערכת הקצאת זיכרון אחרונה (LIFO)לגישה לזיכרון זה ניתן להגיע באמצעות טכניקות מורכבות לניהול זיכרון הכוללות דור צעיר, דור ישן או קבוע, ודור קבוע.
חַיִיםזיכרון הערימה קיים רק כל עוד השיטה הנוכחית פועלתשטח הערימה קיים כל עוד היישום פועל
יְעִילוּתיחסית הרבה יותר מהיר להקצאה בהשוואה לערמהאיטי יותר להקצאה בהשוואה לערימה
הקצאה / הקצאהזיכרון זה מוקצה אוטומטית וממוקד כאשר שיטה מתקשרת ומחוזרת בהתאמהשטח ערימה מוקצה כאשר אובייקטים חדשים נוצרים ומוקצים על ידי אספן Gargabe כאשר הם כבר לא מופנים

6. מסקנה

ערימה וערמה הן שתי דרכים בהן Java מקצה זיכרון. במאמר זה הבנו כיצד הם עובדים ומתי להשתמש בהם לפיתוח תוכניות Java טובות יותר.

למידע נוסף על ניהול זיכרון ב- Java, עיין במאמר זה כאן. דנו גם במאסף האשפה של JVM עליו נדון בקצרה במאמר זה.


$config[zx-auto] not found$config[zx-overlay] not found