ניהול זיכרון בשאלות ראיון עם Java (+ תשובות)

מאמר זה הוא חלק מסדרה: • שאלות ראיונות בנושא אוספי Java

• שאלות בנושא ראיונות מערכת מסוג Java

• שאלות על ראיונות במקביל ל- Java (+ תשובות)

• שאלות על ראיונות מבנה כיתת Java ו אתחול

• Java 8 שאלות ראיונות (+ תשובות)

• ניהול זיכרון בשאלות ראיון עם Java (+ תשובות) (מאמר נוכחי) • שאלות ראיונות עם Java Generics (+ תשובות)

• שאלות ראיונות עם בקרת זרימת Java (+ תשובות)

• שאלות על ראיונות חריגים עם Java (+ תשובות)

• שאלות ראיונות בהערות Java (+ תשובות)

• שאלות על ראיונות מסגרת האביב המובילה

1. הקדמה

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

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

מצד שני, המושגים הללו למעשה די נפוצים בראיונות - אז בואו נקפוץ פנימה.

2. שאלות

שאלה 1. מה פירוש ההצהרה "זיכרון מנוהל בג'אווה"?

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

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

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

שאלה 2. מהו איסוף זבל ומה היתרונות שלו?

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

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

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

שאלה 3. האם יש חסרונות באיסוף האשפה?

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

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

שאלה 4. מה פירוש המושג "עצור את העולם"?

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

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

ש 5. מה הם ערימה וערמה? מה שמור בכל אחד ממבני הזיכרון הללו, וכיצד הם קשורים זה לזה?

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

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

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

שאלה 6. מהו אוסף אשפה דורי ומה הופך אותו לגישה פופולרית לאיסוף אשפה?

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

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

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

עם איסוף האשפה הדורי, חפצים מקובצים לפי "גילם" מבחינת מספר מחזורי איסוף האשפה שהם שרדו. בדרך זו, עיקר העבודה התפשטה על פני מחזורי איסוף מינוריים ועיקריים שונים.

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

ש 7. תאר בפירוט כיצד עובד אוסף הזבל הדורי

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

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

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

התנאי "גיל" באיסוף זבל דורי מתייחס למספר מחזורי האיסוף שהאובייקט שרד.

מרחב הדור הצעיר מחולק עוד יותר לשלושה חללים: מרחב עדן ושני מרחבי שורדים כמו הישרדות 1 (s1) ושורד 2 (s2).

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

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

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

במהלך ה- GC הקטין הבא, אותו דבר קורה למרחב עדן. אובייקטים שלא הוזכרו נמחקים ואובייקטים שהפניה אליהם מועברים למרחב ניצולים. עם זאת, במקרה זה, הם מועברים למרחב הניצולים השני (S2).

בנוסף, אובייקטים מה- GC הקטן האחרון בחלל הניצולים הראשון (S1) מגדילים את גילם ומועברים ל- S2. לאחר העברת כל האובייקטים ששרדו ל- S2, פינוי שטח S1 וגם עדן. בשלב זה, S2 מכיל אובייקטים עם גילאים שונים.

ב- GC הקטין הבא אותו תהליך חוזר על עצמו. אולם הפעם חללי הניצולים עוברים. אובייקטים להפניה מועברים ל- S1 גם מ- Eden ו- S2. אובייקטים ששרדו מיושנים. עדן ו- S2 מנוקים.

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

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

ש 8. מתי אובייקט זכאי לאיסוף אשפה? תאר כיצד ה- Gc אוסף אובייקט זכאי?

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

המקרה הכי פשוט של אובייקט שהופך להיות כשיר לאיסוף אשפה הוא אם כל ההפניות שלו אפסות. תלות מחזורית ללא כל התייחסות חיצונית חיה זכאית גם ל- GC. אז אם אובייקט A מפנה לאובייקט B ואובייקט B מפנה לאובייקט A ואין להם שום הפניה חיה אחרת, אז גם אובייקטים A וגם B יהיו זכאים לאיסוף אשפה.

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

שאלה 9. איך מפעילים אוסף זבל מקוד Java?

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

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

בנוסף, ישנן שיטות כמו System.gc () ו- Runtime.gc () המשמשות למשלוח בקשה לאיסוף אשפה ל- JVM אך לא מובטח שאיסוף האשפה יתרחש.

ש 10. מה קורה כשאין מספיק מקום גדול לאחסון חפצים חדשים?

אם אין מקום זיכרון ליצירת אובייקט חדש ב- Heap, Java Machine Machine זורק OutOfMemoryError או ליתר דיוקjava.lang.OutOfMemoryError שטח ערימה.

שאלה 11. האם ניתן "להחיות" חפץ שזכאי לאיסוף אשפה?

כאשר אובייקט הופך להיות כשיר לאיסוף אשפה, ה- GC צריך להפעיל את לְסַכֵּם שיטה עליו. ה לְסַכֵּם מובטחת שהשיטה תפעל פעם אחת בלבד, ובכך ה- GC מסמן את האובייקט כסופי ונותן לו מנוחה עד למחזור הבא.

בתוך ה לְסַכֵּם שיטה אתה יכול טכנית "להחיות" אובייקט, למשל, על ידי הקצאתו ל- סטָטִי שדה. האובייקט יהפוך לחיים שוב ואינו כשיר לאיסוף אשפה, כך שה- GC לא אוסף אותו במהלך המחזור הבא.

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

שאלה 12. תאר הפניות חזקות, חלשות, רכות ופנטיות ותפקידן באוסף הזבל.

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

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

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

StringBuilder sb = StringBuilder חדש ();

בקטע הקודם, חָדָשׁ מילת מפתח יוצרת חדש StringBuilder להתנגד ולאחסן אותו בערימה. המשתנה sb ואז חנויות א התייחסות חזקה לאובייקט זה. מה זה אומר עבור אספן האשפה הוא שהפרט StringBuilder האובייקט אינו זכאי לאיסוף כלל בשל התייחסות חזקה המוחזקת עליו sb. הסיפור משתנה רק כאשר אנו מבטלים sb ככה:

sb = null;

לאחר קריאה לשורה שלעיל, האובייקט יהיה כשיר לאיסוף.

אנו יכולים לשנות את הקשר הזה בין האובייקט לבין אספן האשפה על ידי גלישתו במפורש בתוך אובייקט ייחוס אחר שנמצא בפנים java.lang.ref חֲבִילָה.

א התייחסות רכה ניתן ליצור לאובייקט הנ"ל כך:

StringBuilder sb = StringBuilder חדש (); SoftReference sbRef = SoftReference חדש (sb); sb = null;

בקטע הקוד לעיל, יצרנו שתי הפניות ל- StringBuilder לְהִתְנַגֵד. השורה הראשונה יוצרת a התייחסות חזקהsb והשורה השנייה יוצרת a התייחסות רכהsbRef. השורה השלישית אמורה להפוך את האובייקט כשיר לאיסוף אך אספן האשפה ידחה את איסוףו בגלל sbRef.

הסיפור ישתנה רק כאשר הזיכרון יהפוך צפוף ו- JVM נמצא על סף זריקת OutOfMemory שְׁגִיאָה. במילים אחרות, אובייקטים עם אזכורים רכים בלבד נאספים כמוצא אחרון לשחזור זיכרון.

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

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

ש 13. נניח שיש לנו הפניה מעגלית (שני אובייקטים שמפנים זה לזה). האם זוג חפצים כזה יכול להיות כשיר לאיסוף אשפה ומדוע?

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

ש 14. כיצד מיצגים מיתרים בזיכרון?

א חוּט מופע ב- Java הוא אובייקט עם שני שדות: א ערך char [] שדה ו int has שדה. ה ערך שדה הוא מערך של תווים המייצגים את המחרוזת עצמה ואת ה- בְּלִיל שדה מכיל את hashCode של מחרוזת שמאותחלת עם אפס, המחושבת במהלך הראשון hashCode () התקשר ושמור במטמון מאז. כמקרה קצה מוזר, אם א hashCode של מחרוזת יש ערך אפס, יש לחשב אותו מחדש בכל פעם ש- hashCode () נקרא.

הדבר החשוב הוא ש חוּט ניתן לשנות את המופע: אינך יכול להשיג או לשנות את הבסיס לְהַשְׁחִיר[] מַעֲרָך. מאפיין נוסף של מיתרים הוא כי המיתרים הקבועים הסטטיים נטענים ושומרים במטמון בבריכת מיתרים. אם יש לך מספר זהה חוּט אובייקטים בקוד המקור שלך, כולם מיוצגים על ידי מופע יחיד בזמן ריצה.

ש 15. מהו מיתרי מיתרים ומהם מקרי השימוש בו? מה ההבדל בין הוספת מחרוזת לבניית מיתרים לבין שרשור שני מיתרים עם מפעיל +? במה שונה מיתרי מיתרים מסטרינגבופר?

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

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

StringBuffer שונה מ StringBuilder בכך שהוא בטוח בחוטים. אם אתה צריך לתפעל מחרוזת בשרשור יחיד, השתמש StringBuilder במקום זאת.

3. מסקנה

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

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

הַבָּא » שאלות על ראיונות עם Java Generics (+ תשובות) « שאלות קודמות בנושא Java 8 (+ תשובות)

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