Нужно ли мне беспокоиться о пуле строковых констант?

#java #string

Вопрос:

У меня есть Java-приложение, которое очень сильно нагружено строками — оно принимает огромное количество больших, разных строковых объектов.

Нужно ли мне беспокоиться о постоянном пуле строк для памяти и производительности?

Есть ли какой-нибудь способ узнать, насколько велик пул в любой момент?

Комментарии:

1. для jvm sun используйте jmap-permstat, чтобы увидеть, сколько памяти используется внутренними строками

Ответ №1:

Как сказал Марио, пул констант относится только к строкам intern()ed и к строкам, которые являются константами в коде java (они неявно интернированы).

Но есть еще одно предостережение, которое может быть применимо к вашему случаю: substring() метод будет совместно использовать базовую char[] строку с исходной строкой. Итак, схема

   String large = ...                  // read 10k string
  String small = large.substring(...) // extrakt a few chars
  large = null;  // large String object no longer reachable,
                 // but 10k char[] still alive, as long as small lives
 

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

Комментарии:

1. Хорошо, я не знал этого предостережения. Существует конструктор пакета, который принимает символ[] в качестве аргумента и содержит сильную ссылку. Так что же делать, если нам действительно нужна копия только подстроки?

2. Строка маленькая = новая строка(большая.подстрока(…))

Ответ №2:

Если это поток объектов, то они не попадают в пул строковых констант, если вы не вызовете intern (), насколько я знаю. Потребление памяти для интернированных строк происходит не из кучи, а из пространства памяти постоянного поколения, поэтому, если вы интернируете много строк, приложение завершит работу с OutOfMemory, даже если останется много кучи.

Так что это не должно вызывать беспокойства, если вы не интернируете все эти строки. Если это станет проблемой, можно было бы иметь собственную реализацию карты для хранения этих строк, поэтому вы не используете внутренний механизм.

Я проверил реализацию метода intern (), и он является встроенным, поэтому, похоже, не так просто измерить потребление памяти или просмотреть содержимое пула.

Вы можете использовать этот флаг для увеличения размера разрешения, если у вас заканчивается память:

 -XX:MaxPermSize=64m
 

Ответ №3:

Я думаю, что вам следует профилировать свою заявку, как с стажировкой, так и без нее. Тогда вы точно увидите, каков эффект.

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

Ответ №4:

Не зная точно, что это за программа, я могу только предложить вам попытаться использовать строки как поток, а не хранить строку в целом. Возможно, вам нужно сделать больше абстракций для вашего приложения и изобрести промежуточное представление, которое более эффективно использует память?

Ответ №5:

В Java 1.7 подстрока() — метод больше не использует тот же символ [], вместо этого он копирует подстроку в новый массив, т. е.

 public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) amp;amp; (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
 

которые все в строковый конструктор, если beginIndex не равен нулю или endIndex не равен длине массива char [].

 public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset   count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset count);
    }