Clear string pool java

Руководство по пулу строк 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 .

Источник

Как удаляются неиспользуемые значения из пула строк?

В случае GC, «ABC» из кучи собирается, но «ABC» все еще находится в пуле (потому что его в permGen и GC не повлияют на него).

Если мы продолжим добавлять такие значения, как:

String c = "ABC"; // pointing to 'ABC' in the pool. for(int i=0; i < 10000; i++) < c = ""+i; // each iteration adds a new value in the pool. Previous values don't have a pointer. >
  • Удалит ли пул значения, на которые нет ссылок? Если нет, значит, пул съедает лишнюю память.
  • В чем тогда смысл, потому что JVM использует пул?
  • Когда это может быть риском для производительности?

c отсутствует в пуле, и строки неизменяемы. Вы создаете новую строку каждый раз при объединении, а ее нет в пуле.

Это похоже на оптимизацию («ABC» + «D»). Я предлагаю создавать строки в двух циклах, а затем сравнивать их. Это сложнее оптимизировать 🙂

c сначала ссылается на строку в пуле, а затем — нет. Ваш пример плохой, потому что Java будет объединяться во время компиляции.

1 ответ

String c = "ABC"; // pointing to 'ABC' in pool. for(int i=0; i < 10000; i++) < c = ""+i; // each iteration add new value in pool. and pervious values has no pointer >

В пуле будут только два объекта String , два из которых происходят от двух литералов String , «ABC» и «» . Каждый другой String , созданный в результате конкатенации, будет обычным объектом с обычным поведением сборщика мусора, т.е. кандидат на сбор, когда они больше не доступны.

Значения String , поступающие из литералов String в пуле, не собираются, поскольку они всегда доступны (YMMV с загрузчиками классов). Объекты String , которые интернированы, но не происходят из литералов, должны регулярно становиться кандидатами на сборку мусора.

Я знаю, что мой примерный код был плохим. каким бы то ни было образом ссылки, которые вы предоставили, были полезны. благодаря.

Источник

Can we delete a String Object from JVM String Pool?

send pies

posted 11 years ago

  • Report post to moderator
  • Sheriff

    Chrome

    send pies

    posted 11 years ago

  • Report post to moderator
  • Nope. If you don’t want a String to be in the String pool, you must make sure it doesn’t get put into it in the first place: don’t use it as a String literal, and don’t intern() it.

    SCJP 1.4 — SCJP 6 — SCWCD 5 — OCEEJBD 6 — OCEJPAD 6
    How To Ask Questions How To Answer Questions

    send pies

    posted 11 years ago

  • Report post to moderator
  • Rob Spoor wrote: Nope. If you don’t want a String to be in the String pool, you must make sure it doesn’t get put into it in the first place: don’t use it as a String literal, and don’t intern() it.

    We are using some java libraries which only return String, and we want to delete those String once used, because they are too large to be occupied in memory, causing OutOfMemoryError.

    Sheriff

    Chrome

    send pies

    posted 11 years ago

  • Report post to moderator
  • Are you sure they are the reason for the memory error? String literals don’t take up much memory, unless they are either very very long or very very numerous.

    Are you even sure they are String literals, and not non-interned Strings? These should be garbage collected as usual.

    Part of your problem may be that you are still holding a reference to them, or perhaps to their internal char[]. When you call substring on a String, that substring shares the original String’s char[]. If the substring is much smaller than the original, that is a waste of memory. This is one of the few cases where using copying the String makes sense. So if this is the case, use the following to create substrings:
    This will create a new String that does not share the char[], and therefore this char[] can be garbage collected too.

    SCJP 1.4 — SCJP 6 — SCWCD 5 — OCEEJBD 6 — OCEJPAD 6
    How To Ask Questions How To Answer Questions

    Источник

    Читайте также:  Javascript operators ternary operator
    Оцените статью