Java string pool size

String Pool | Java

String pool in Java is a pool of String literals and interned Strings in JVM for efficient use of String object. Since String is Immutable Class In Java, it makes sense to cache and shares them in JVM. Java creators introduced this String pool construct as an optimization on the way String objects are allocated and stored. It is a simple implementation of the Flyweight pattern, which in essence, says this: when a lot of data is common among several objects, it is better to just share the same instance of that data than creating several different “copies” of it.

There are mainly two ways to create a string.

String myString = new String(«Hello!! Pumpkin»)

Whenever a String is created using direct initialization, the JVM checks for the String in the Java Heap memory.
If a String with the same value is found, then only the reference of the String that is already present is pointed to the new String that we want to create.
If the string is created using new constructor then it will get allocated new space in heap regardless of the object exists in pool or not. The same is illustrated in the below image.

String Pool Java6 vs Java7 vs Java8

As the string is immutable, when you try to modify the value of the String that you have created from String Pool, a new String is created or reference from String Pool.

Читайте также:  Write comments in php

String Pool helps the java heap memory to be used optimally, as few Strings are created on the Java Heap. This helps in less work for the garbage collector.

Let’s see JVM string pool implementation in Java 6, 7 and 8
Java6

The string pool is implemented as a fixed capacity HashMap with each bucket containing a list of strings with the same hashCode. The default size of the table/pool is 1,009 buckets. It was a constant in the early versions of Java 6 and became configurable between Java6u30 and Java6u41. You need to specify – XX: StringTableSize =N , where N is the string pool map size.
String pool was located in PermGen Space which is very limited.

Java7 (until Java7u40)

String pool moved from PermGen space to heap space. You are limited only by a much higher heap size. It means that you can set the string pool size to a rather high value in advance (this value depends on your application requirements). As a rule, one starts worrying about the memory consumption when the memory data set size grows to at least several hundred megabytes. In this situation, allocating 8-16 MB for a string pool with one million entries seems to be a reasonable trade off.

Java8

String pool size was increased in Java7u40 (this was a major performance update) to 60013. This value allows you to have approximately 30,000 distinct strings in the pool before you start experiencing collisions. Java 8 still accepts – XX: StringTableSize parameter and provides the comparable to Java 7 performance. The only important difference is that the default pool size was increased in Java 8 to 60013.

You can also read codepumpkin’s series of articles on JVM Internals.

That’s all for this topic. If you guys have any suggestions or queries, feel free to drop a comment. We would be happy to add that in our post. You can also contribute your articles by creating contributor account here.

If you like the content on CodePumpkin and if you wish to do something for the community and the planet Earth, you can donate to our campaign for planting more trees at CodePumpkin Cauvery Calling Campaign.

We may not get time to plant a tree, but we can definitely donate ₹42 per Tree.

Источник

What if Size of String Pool Exceeds?

In Java, String literals in String Constant Pool are not garbage collected, since they are referenced from Table of references which is created by instance of runtime in order to optimize space. If Size of String literal pool exceeds then, Since each String in String literal pool has reference hence it will be not eligible for GC. how it is handled by JVM ?

Strings in the constant pool can be garbage collected if they are no longer needed (i.e. the classes that put them there are unloaded).

2 Answers 2

There is a long discussion with real code examples at JavaRanch.

The general output is the following:

  1. If a string is added to constant pool at RUNTIME using String.intern(), it can be garbage collected after it is no longer in use. Most probably, the string pool keeps only soft references to added strings, thus allowing to garbage collect them (can’t be sure, because String.intern() is a native method).
  2. If a string is a COMPILE time constant, it is added to the constant pool of the corresponding class. Therefore, it can be garbage collected only after the class is unloaded.

The answer to your question is: the only way how you can get OutOfMemoryError because of String constants is to load lot’s of classes with many string literals computed at compile time. Then you can eventually exceed maximum size of PermGen space. But this will happen at the time you load classes into memory (e.g., start your application, deploy project to a WebServer, dynamically load new library, etc.)

String literals can be collected when they are no longer needed. Usually this is not a problem if they appear in classes because there are other limits you are likely to reach if you attempt to load lots of classes e.g. Maximum Perm Gen.

Generally speaking, developers are smart enough not to over use the string literal pool and instead using databases or file to load the bulk of their data if its a non trivial size.

You can introduce a problem if you use String.intern() a lot in an attempt to optimise the space of your system. String.intern() is not free and becomes increasingly expensive if you add a large number (millions) of string into it. If this is a performance problem, it should be reasonably obvious to the developer when it is.

Источник

Руководство по пулу строк Java

Объект String является наиболее часто используемым классом в языке Java.

В этой быстрой статье мы рассмотрим пул строк Java — специальную область памяти, в которой JVM хранит строки .

2. Стажировка строк

Благодаря неизменности строк в Java, JVM может оптимизировать объем выделяемой для них памяти, сохраняя в пуле только одну копию каждой литеральной строки . Этот процесс называется интернированием .

Когда мы создаем переменную String и присваиваем ей значение, JVM ищет в пуле строку с равным значением.

Если он найден, компилятор Java просто вернет ссылку на свой адрес памяти, не выделяя дополнительной памяти.

Если он не найден, он будет добавлен в пул (интернирован), и его ссылка будет возвращена.

Давайте напишем небольшой тест, чтобы проверить это:

 String constantString1 = "ForEach";   String constantString2 = "ForEach";    assertThat(constantString1)   .isSameAs(constantString2); 

3. Строки , выделенные с помощью конструктора

Когда мы создаем String с помощью оператора new , компилятор Java создаст новый объект и сохранит его в пространстве кучи, зарезервированном для JVM.

Каждая строка , созданная таким образом, будет указывать на другую область памяти со своим собственным адресом.

Давайте посмотрим, чем это отличается от предыдущего случая:

 String constantString = "ForEach";   String newString = new String("ForEach");    assertThat(constantString).isNotSameAs(newString); 

4. Строковый литерал против строкового объекта

Когда мы создаем объект String с помощью оператора new() , он всегда создает новый объект в куче памяти. С другой стороны, если мы создадим объект, используя синтаксис строкового литерала, например, « ForEach », он может вернуть существующий объект из пула строк, если он уже существует. В противном случае он создаст новый объект String и поместит его в пул строк для повторного использования в будущем.

На высоком уровне оба являются объектами String , но основное различие заключается в том, что оператор new() всегда создает новый объект String . Кроме того, когда мы создаем строку , используя литерал, она интернируется.

Это станет намного яснее, если мы сравним два объекта String , созданные с использованием литерала String и оператора new :

 String first = "ForEach";   String second = "ForEach";   System.out.println(first == second); // True 

В этом примере объекты String будут иметь одну и ту же ссылку.

Далее создадим два разных объекта с помощью new и проверим, что у них разные ссылки:

 String third = new String("ForEach");   String fourth = new String("ForEach");   System.out.println(third == fourth); // False 

Точно так же, когда мы сравниваем литерал String с объектом String, созданным с помощью оператора new() с помощью оператора ==, он вернет false:

 String fifth = "ForEach";   String sixth = new String("ForEach");   System.out.println(fifth == sixth); // False 

В общем, мы должны использовать литеральную нотацию String , когда это возможно . Его легче читать, и он дает компилятору возможность оптимизировать наш код.

5. Стажировка вручную

Мы можем вручную интернировать строку в пуле строк Java, вызвав метод intern() для объекта, который мы хотим интернировать.

Интернирование строки вручную сохранит ее ссылку в пуле, и JVM вернет эту ссылку при необходимости.

Давайте создадим тестовый пример для этого:

 String constantString = "interned ForEach";   String newString = new String("interned ForEach");    assertThat(constantString).isNotSameAs(newString);    String internedString = newString.intern();    assertThat(constantString)   .isSameAs(internedString); 

6. Сбор мусора

До Java 7 JVM помещала Java String Pool в пространство PermGen , которое имеет фиксированный размер — его нельзя расширить во время выполнения и нельзя использовать для сборки мусора .

Риск интернирования Strings в PermGen (вместо Heap ) заключается в том, что мы можем получить ошибку OutOfMemory от JVM, если интернируем слишком много Strings .

Начиная с Java 7, пул строк Java хранится в пространстве кучи , которое является мусором , собираемым JVM . Преимущество этого подхода заключается в снижении риска ошибки OutOfMemory , поскольку строки , на которые нет ссылок , будут удалены из пула, тем самым освобождая память.

7. Производительность и оптимизация

В Java 6 единственная оптимизация, которую мы можем выполнить, — это увеличение пространства PermGen во время вызова программы с параметром JVM MaxPermSize :

В Java 7 у нас есть более подробные параметры для проверки и расширения/уменьшения размера пула. Рассмотрим два варианта просмотра размера пула:

 -XX:+PrintStringTableStatistics 

Если мы хотим увеличить размер пула с точки зрения сегментов, мы можем использовать параметр StringTableSize JVM:

До Java 7u40 размер пула по умолчанию составлял 1009 сегментов, но в более поздних версиях Java это значение претерпело некоторые изменения. Если быть точным, размер пула по умолчанию от Java 7u40 до Java 11 составлял 60013, а теперь он увеличился до 65536.

Обратите внимание, что увеличение размера пула потребует больше памяти, но имеет то преимущество, что сокращает время, необходимое для вставки строк в таблицу.

8. Примечание о Java 9

До Java 8 строки были внутренне представлены как массив символов — char[] , закодированный в UTF-16 , так что каждый символ использует два байта памяти.

В Java 9 предоставляется новое представление, называемое компактными строками. Этот новый формат выберет подходящую кодировку между char[] и byte[] в зависимости от сохраненного содержимого.

Поскольку новое представление String будет использовать кодировку UTF-16 только при необходимости, объем памяти кучи будет значительно меньше, что, в свою очередь, приведет к меньшим накладным расходам сборщика мусора на JVM.

9. Заключение

В этом руководстве мы показали, как JVM и компилятор Java оптимизируют выделение памяти для объектов String через Java String Pool.

Все примеры кода, использованные в статье, доступны на GitHub .

Источник

Оцените статью