כפי שידוע לנו, לא נהוג לבדוק ערך של String על ידי == אלא על ידי
equals(). הסיבה היא שהשוואת == בודקת האם מדובר באותו
מיקום בזיכרון (אותו reference).
אבל בכל זאת הדוגמה הבאה תחזיר לנו true:
String s1 = "hello java";
String s2 = "hello java";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
אז מה בעצם קרה פה?
כמו ב-Integer Pool, גם String אינו מוזנח ב-Java. על מנת לחסוך בזיכרון ולנהל משאבים בצורה יעילה, Java שומרת String literals בתוך מאגר מיוחד הנקרא String Pool.
למידע נוסף על Integer Pool:
אם ניצור String באמצעות new, ההשוואה באמצעות
== לא תעבוד, מכיוון שהאובייקט החדש אינו משתמש ברפרנס
שנמצא ב-String Pool.
String s3 = new String("hello java");
System.out.println(s2 == s3);
System.out.println(s2.equals(s3));
התוצאה תהיה:
אם נשתמש בפקודת intern(), ההשוואה בשתי התצורות תחזיר
true.
String s4 = s3.intern();
System.out.println(s2 == s4);
System.out.println(s2.equals(s4));
מה בעצם קרה כאן?
הפקודה intern() ניגשת ל-String Pool ובודקת האם המחרוזת
"hello java" כבר קיימת שם.
לדוגמה:
UUID.randomUUID().toString().intern();
הקוד הזה יכניס אלפי ערכים שונים ל-Pool ויגדיל אותו ללא צורך. מכיוון שכל UUID הוא ייחודי, אין סיבה אמיתית לשמור אותו ב-String Pool.
ב-Java קיימים שני אזורי זיכרון עיקריים:
String s1 = "hello java";
מה קורה בזיכרון?
String s3 = new String("hello java");
כאן ייווצר אובייקט חדש לחלוטין ב-Heap.
התיאור למעלה מתאים ל-Java 8 ומעלה, אך בעבר המצב היה שונה.
ב-Java 7 ומטה היה אזור מיוחד בשם PermGen (Permanent Generation).
PermGen היה חלק מהזיכרון של ה-JVM והכיל בעיקר metadata של מחלקות וכן מידע נוסף שהמערכת הגדירה כ"קבוע".
עם השנים התברר שיש בעיה בגישה זו:
לכן Java 8 החליפה את PermGen ב-Metaspace.
Metaspace משתמש ב-Native Memory של מערכת ההפעלה ויכול לגדול בצורה דינמית בהתאם לצורך.
זה לא אומר שהזיכרון אינסופי – גם כאן ניתן להגיע למגבלה, אך המגבלה גדולה וגמישה בהרבה לעומת PermGen.