Я правильно интернирую свои строки? - PullRequest
4 голосов
/ 29 мая 2009

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

Эти два утверждения эквивалентны?

String s1 = ( "hello" + "world" ).intern(); 

String s2 = "hello".intern() + "world".intern();

UPDATE

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

public String toAddress( Transport transport )
{
    Constraint.NonNullArgument.check( transport, "transport" );

    switch( transport )
    {
    case GOOGLE:
    case MSN:
        return ( transport.code() + PERIOD + _domain ).intern();
    case YAHOO:
    default:
        return _domain;
    }
}
private String _domain;  // is initialized during constructor
private static final String PERIOD = ".";

Ответы [ 9 ]

10 голосов
/ 29 мая 2009

Как говорит Дженсграм, эти два утверждения не эквивалентны. Два важных правила:

  • Объединение строковых литералов в коде заканчивается строковой константой, поэтому эти два оператора точно эквивалентны (они будут выдавать идентичный байт-код):

    String x = "foo" + "bar":
    String x = "foobar";
    
  • Строковые константы интернируются автоматически, вам не нужно делать это явно

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

РЕДАКТИРОВАТЬ: Хорошо, основываясь на редактировании вопроса: это может сэкономить немного памяти , если , то вы в конечном итоге сохраните возвращаемое значение toAddress() где-нибудь, для чего оно останется долгое время и вы будете иметь один и тот же адрес несколько раз. Если эти не , дело в том, что стажировка, скорее всего, только ухудшит ситуацию. Я не знаю наверняка, остаются ли интернированные строки навсегда, но это вполне возможно.

Мне кажется, что вряд ли будет хорошим вариантом интернирования, и, скорее всего, будет только усугублять ситуацию. Вы упомянули, что пытались сэкономить место на пермгене - почему вы считаете, что интернирование там поможет? Связанные строки в любом случае не окажутся в permgen, если я не сильно ошибаюсь.

10 голосов
/ 29 мая 2009

Лучший совет, который я могу придумать: не беспокойтесь. Статически объявленные строки будут находиться в постоянном пуле в любом случае, если только вы динамически не создаете строку, которая ... ошибается, я не могу придумать причину.

Я программирую на Java с 97 года и никогда не использовал String.intern().

РЕДАКТИРОВАТЬ: После просмотра вашего обновления я действительно считаю, что вы не должны использовать intern (). Ваш метод выглядит совершенно нормально, и там практически нет причин использовать intern ().

Моя причина в том, что это заражение оптимизации, и, возможно, преждевременное, вы второй угадываете сборщик мусора. Если метод just of you недолговечен, то получившаяся строка очень скоро умрет молодому поколению в следующем минорном GC, и если это не так, он будет интернирован (из-за отсутствия лучшего слова) в любом случае в зрелом поколении .

Полагаю, единственное время, когда это может быть хорошей идеей, - это потратить немного времени на профилировщик и доказать, что это сильно влияет на производительность вашего приложения.

7 голосов
/ 29 мая 2009

Нет. Добавление двух интернированных строк не дает интернированную строку.

Тем не менее, довольно редко нужно "тщательно интернировать свои струны". Если вы не имеете дело с огромным количеством одинаковых строк, это больше проблем, чем стоит.

2 голосов
/ 29 мая 2009

Возможно, вы захотите получить какое-то доказательство (возможно, посредством профилирования), что вы «разбиваете пространство permgen», прежде чем писать весь свой код таким образом.

В противном случае вы можете просто выполнять «преждевременную оптимизацию», которая обычно вызывает недовольство. См. http://en.wikipedia.org/wiki/Optimization_(computer_science)#When_to_optimize для более подробной информации о том, почему это может быть плохо.

2 голосов
/ 29 мая 2009

Дополнительная информация поможет нам понять ваш запрос ... В любом случае ...

Если вы хотите вручную пройти стажировку для HelloWorld, тогда переходите к первому утверждению, как и во втором утверждении, которое вы проходите через Hello и World отдельно. Два утверждения совсем не идентичны.

2 голосов
/ 29 мая 2009

Я бы сказал нет. s1 добавляет "helloworld" в пул, тогда как s2 состоит из двух объединенных строк "hello" и "world".

0 голосов
/ 29 мая 2009

интернирование строк - это, по сути, утечка памяти, ожидающая: (

Если у вас нет очень, очень веской причины [1], не делайте этого, но оставьте это JVM.

[1] Как в «Дорогой босс, пожалуйста, не увольняй меня. У меня есть эти данные профилирования, чтобы подтвердить мое решение использовать интерна»:)

0 голосов
/ 29 мая 2009

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

0 голосов
/ 29 мая 2009

Во многих случаях «тщательная обработка» ваших строк не дает вам ничего, кроме некоторого времени. Рассмотрим следующий случай:

void foobar(int x) {
  String s1 = someMethod(x).intern();
  ...
  ...
}

То есть s1 интернирован, пространство в куче не потеряно? Неправильно! Скорее всего, промежуточный результат someMethod (x) все еще существует где-то в куче и нуждается в сборке мусора. Это потому, что someMethod () каким-то образом сконструировал строку и (если он не возвращает литерал) сделал это в куче. Но тогда ... лучше посмотрите, для чего используется пространство permgen. Он используется для метаданных о классах и (ooops) таблице String.intern. Интернируя все свои строки, вы делаете именно то, что хотели избежать: разбейте пространство permgen.

Больше информации здесь: http://www.thesorensens.org/2006/09/09/java-permgen-space-stringintern-xml-parsing/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...