Подтвердить что ты не робот

Поведение коллекции мусора для String.intern()

Если я использую String.intern() для повышения производительности, поскольку я могу использовать "==" для сравнения интернированной строки, я буду сталкиваться с проблемами сбора мусора? Как механизм сбора мусора интернированных строк отличается от обычных строк?

4b9b3361

Ответ 1

Фактически, это не оптимизация коллекции мусора, а скорее оптимизация пула строк. Когда вы вызываете String.intern(), вы заменяете ссылку на свою начальную строку ссылкой на базовую ссылку (ссылка на первый раз, когда эта строка встречалась, или эта ссылка, если она еще не известна).

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

Как правило, я считаю предпочтительным никогда использовать этот метод intern и позволить компилятору использовать его только для констант Строки, объявленные следующим образом:

String myString = "a constant that will be interned";

Это лучше, так как это не позволит вам сделать ложное предположение == может работать, когда оно не будет.

Кроме того, факт String.equals лежит в основе == как оптимизация, что делает возможным оптимизацию интернированных строк под капотом. Это еще одно доказательство ==, если никогда использоваться для строк.

Ответ 2

String.intern() управляет внутренним пулом, реализованным на основе собственной реализации, который имеет некоторые специальные функции, связанные с GC. Это старый код, но если он был реализован заново, он использовал бы java.util.WeakHashMap. Слабые ссылки - это способ сохранить указатель на объект, не мешая ему собираться. Правильная вещь для объединенного пула, такого как интернированные строки.

Эти интернированные строки собирают мусор, которые можно продемонстрировать со следующим кодом Java:

public class InternedStringsAreCollected {

    public static void main(String[] args)
    {
        for (int i = 0; i < 30; i ++) {
            foo();  
            System.gc();
        }   
    }

    private static void foo()
    {
        char[] tc = new char[10];
        for (int i = 0; i < tc.length; i ++)
            tc[i] = (char)(i * 136757);
        String s = new String(tc).intern();
        System.out.println(System.identityHashCode(s));
    }
}

Этот код создает 30 раз одну и ту же строку, каждый раз интернируя ее. Кроме того, он использует System.identityHashCode(), чтобы показать, какой хэш-код Object.hashCode() был бы возвращен на эту интернированную строку. При запуске этот код печатает четкие целочисленные значения, а это означает, что вы не получаете один и тот же экземпляр каждый раз.

В любом случае использование String.intern() несколько обескуражено. Это общий статический пул, что означает, что он легко превращается в узкое место в многоядерных системах. Используйте String.equals() для сравнения строк, и вы будете жить дольше и счастливее.

Ответ 3

В этой статье приведен полный ответ.

В java 6 пул строк находится в PermGen, так как java 7 пул строк находится в памяти кучи.

Ручные интернированные строки будут собраны в мусор.
Строковые литералы будут собирать только мусор, если класс, который их определяет, выгружается.

Пул строк - это HashMap с фиксированным размером, который был небольшим в java 6 и ранних версиях java 7, но увеличился до 60013 с java 7u40.
Его можно изменить с помощью -XX: StringTableSize = < new size > и просмотреть с параметрами -XX: + PrintFlagsFinal java.

Ответ 4

Пожалуйста, прочитайте: http://satukubik.com/2009/01/06/java-tips-memory-optimization-for-string/

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