Как JVM работает со строками, часть 1
По статистике OpenJDK в приложениях 15-50% памяти занимают экземпляры String. Это много, поэтому разработчики JVM прикладывают много усилий, чтобы оптимизировать работу со строками.
❓Как сэкономить память, если в системе миллионы экземпляров?
1️⃣ Уменьшить количество памяти под одну строку.
Мы уже разбирали этот случай: в java 9 вышло обновление Compact String и размер памяти под строки сократился до 2 раз.
2️⃣ Добавить кэширование.
Есть два способа создать экземпляр String:
🔸Через оператор new:
🔸Без оператора new:
▫️Проверить в String Pool, есть ли там такая строка.
▫️Если есть — вернуть её.
▫️Если нет — создать объект, поместить в кэш, вернуть.
❓Как реализован String pool?
Структура похожа на HashMap: хэш-таблица фиксированного размера с парами хэш — строка. В последних версиях java она занимает 64 МБ, при желании размер меняется с помощью флажка:
✅ Ответ на 1 вопрос перед постом:
Можно исправить ситуацию и добавить строчку в кэш методом intern():
Но если строка "Java" использовалась раньше и попала в кэш, то будет создана только одна строка — new String.
По статистике OpenJDK в приложениях 15-50% памяти занимают экземпляры String. Это много, поэтому разработчики JVM прикладывают много усилий, чтобы оптимизировать работу со строками.
❓Как сэкономить память, если в системе миллионы экземпляров?
1️⃣ Уменьшить количество памяти под одну строку.
Мы уже разбирали этот случай: в java 9 вышло обновление Compact String и размер памяти под строки сократился до 2 раз.
2️⃣ Добавить кэширование.
Есть два способа создать экземпляр String:
🔸Через оператор new:
String s = new String ("one");В памяти создаётся новый объект.
🔸Без оператора new:
String s = "one";В этом случае идёт работа с кэшем строк под названием String pool. Схема работы такая:
▫️Проверить в String Pool, есть ли там такая строка.
▫️Если есть — вернуть её.
▫️Если нет — создать объект, поместить в кэш, вернуть.
❓Как реализован String pool?
Структура похожа на HashMap: хэш-таблица фиксированного размера с парами хэш — строка. В последних версиях java она занимает 64 МБ, при желании размер меняется с помощью флажка:
-XX:StringTableSize=65536В следующем посте рассмотрим ещё два способа снижения издержек на строки.
✅ Ответ на 1 вопрос перед постом:
new String("Java")
создаёт новый объект в хипе, s2 = "Java"
создаёт объект в String pool. Это два разных объекта, поэтому при сравнении через == результат будет false.Можно исправить ситуацию и добавить строчку в кэш методом intern():
String s1="Java";✅Рассмотрим второй вопрос. О том, сколько строк создаётся в конструкции
String s2=new String("Java");
s2=s2.intern();
println(s1==s2); //true
String str=new String("Java");Подвох в том, что для конструктора String нужен экземпляр String, поэтому создаётся 2 строки — "Java" и new String;
Но если строка "Java" использовалась раньше и попала в кэш, то будет создана только одна строка — new String.