Вопрос по string, java – Это хорошая практика, чтобы использовать java.lang.String.intern ()?

192

Javadoc оString.intern() не дает подробностей. (В двух словах: он возвращает каноническое представление строки, позволяя сравнивать интернированные строки, используя==)

Когда бы я использовал эту функцию в пользуString.equals()? Есть ли побочные эффекты, не упомянутые в Javadoc, то есть более или менее оптимизация JIT-компилятором? Есть ли дальнейшее использованиеString.intern()?
Calling intern () имеет свое собственное влияние на производительность. Использование intern () для улучшения производительности требует тестирования, чтобы убедиться, что оно действительно значительно ускоряет вашу программу, чтобы стоить дополнительной сложности. Вы также можете использовать это, чтобы уменьшить потребление памяти для больших таблиц с относительно повторяющимися значениями. Однако в обоих случаях есть другие варианты, которые могут быть лучше. Peter Lawrey
Да, intern () имеет свое влияние на производительность. Тем более, что стоимость intern () увеличивается линейно, когда вы интернируете строки и сохраняете ссылку на них. По крайней мере, на солнце / оракул 1.6.0_30 vm. lacroix1547

Ваш Ответ

20   ответов
124

когда ты нуждаешься Скорость так как вы можете сравнивать строки по ссылке (== быстрее чем равно)

Есть ли побочные эффекты, не упомянутые в Javadoc?

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

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

(от JGuru)

Третий недостаток (только Java 7 или менее): интернированные строки живут в пространстве PermGen, которое обычно довольно мало; вы можете столкнуться с OutOfMemoryError с большим количеством свободного места в куче.

(от Майкла Боргвардта)

Вы все еще можете использовать синтаксис s1.equals во всей программе, НЕ используйте ==, .equals используйте == внутренне для оценки короткого замыкания gtrak
Майкл Боргвардт НЕ сказал, что интернированные строки нельзя собирать. И это ложное утверждение. То, что комментарии Майкла (правильно) говорят, более тонкое, чем это. Stephen C
Третий недостаток: интернированные строки живут в пространстве PermGen, которое обычно довольно мало; вы можете столкнуться с OutOfMemoryError с большим количеством свободного места в куче. Michael Borgwardt
AFAIK более новые виртуальные машины также собирают мусор в пространстве PermGen. Daniel Rikowski
Intern - это управление памятью, а не скорость сравнения. Разница междуif (s1.equals(s2)) а такжеif (i1 == i2) минимально, если у вас много длинных строк с одинаковыми ведущими символами. В большинстве реальных применений (кроме URL) строки будут отличаться в пределах первых нескольких символов. В любом случае, длинные цепочки if-else являются запахом кода: используйте перечисления и функторные карты. kdgregory
2

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

36

String.intern() это определенно мусор, собираемый в современных JVM.
Следующему НИКОГДА не хватает памяти из-за активности GC:

// java -cp .
public class UserOfIntern {
    public static void main(String[] args) {
        Random random = new Random();
        System.out.println(random.nextLong());
        while (true) {
            String s = String.valueOf(random.nextLong());
            s = s.intern();
        }
    }
}

Смотрите больше (от меня) на миф не GCed String.intern ().

@ Seiti Циркулярные ссылки легко обнаружить в эти дни: p Ajay
OutOfMemoryException - нет, не код выше, в моеммоз: ссылка на javaturning статью, которая указывает на эту статью, которая указывает на javaturning статью, которая ...: -) Carlos Heuberger
@ Carlos, связывающий внешнюю ссылку, которая ссылается на stackoverflow, должен вызвать .. Stackoverflow:) Seiti
Вы можете упомянуть, что вы являетесь автором внешней ссылки, на которую вы ссылаетесь. Thorbjørn Ravn Andersen
@ Matthieu ссылка исправлена. спасибо за сообщение. Gili Nachum
1

http: //kohlerm.blogspot.co.uk/2009/01/is-javalangstringintern-really-evil.htm

утверждает, чтоString.equals() использует"==" сравниватьString объекты до, в соответствии с

http: //www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.htm

Это сравнивает длину строк, а затем содержимое.

(Кстати, строки кода продукта в каталоге продаж должны быть одинаковой длины - BIC0417 - это защитный шлем для велосипедиста, TIG0003 - живой взрослый тигр-самец - вам, вероятно, понадобятся все виды лицензий, чтобы заказать одну из них. И, может быть, вам лучше заказать защитный шлем одновременно.)

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

Но делаетString.equals() проверьте, что вы передали ему строку, а не какой-либо другой объект, перед использованием"=="? Я не квалифицирован, чтобы сказать, но я бы не догадался, потому что в подавляющем большинстве такихequals()перации @ будут String to String, так что тест почти всегда проходит. Действительно, расставив приоритеты "==" внутриString.equals() означает, что вы часто сравниваете строку с одним и тем же реальным объектом.

Я надеюсь, что никто не удивится, что следующие строки приводят к результату "false":

    Integer i = 1;
    System.out.println("1".equals(i));

Но если ты поменяешьсяi вi.toString() во второй строке, конечно, этоtrue.

Вы можете надеяться на выгоду от стажировкиSet а такжеMap, очевидно. Я надеюсь, что в интернированных строках кэшируются их хэш-коды ... Я думаю, что это будет требованием. И я надеюсь, что я не просто выдал идею, которая могла бы заработать мне миллион долларов. : -)

Что касается памяти, также очевидно, что это важный предел, если у вас большой объем строк или если вы хотите, чтобы объем памяти, используемой вашим программным кодом, был очень маленьким. Если ваш объем -distinct-Strings очень велик, возможно, пришло время подумать об использовании выделенного программного кода базы данных для управления ими и отдельного сервера базы данных. Аналогично, если вы можете улучшить небольшую программу (которая должна запускаться в 10000 экземпляров одновременно), если она вообще не хранит свои строки.

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

Мне интересно,intern() может использоваться злонамеренным программным кодом для обнаружения того, существуют ли некоторые строки и их ссылки на объекты вintern() pool, и поэтому существуют в другом месте сеанса Java, когда это не должно быть известно. Но это возможно только тогда, когда программный код уже используется доверительно, я думаю. Тем не менее, стоит подумать о сторонних библиотеках, которые вы включаете в свою программу для хранения и запоминания своих ПИН-кодов банкоматов!

16

7 и 8: String.intern в Java 6, 7 и 8 - объединение строк.

Я надеюсь, что он должен содержать достаточно информации о текущей ситуации с пулами строк в Java.

В двух словах

ИзбегайString.intern() в Java 6, потому что он входит в PermGen ПредпочитаюString.intern() в Java 7 и Java 8: он использует в 4-5 раз меньше памяти, чем собственный пул объектов Обязательно настройтесь-XX:StringTableSize (по умолчанию это, вероятно, слишком мало; установите простое число)
Пожалуйста, не размещайте ссылки на свой блог, некоторые считают это СПАМОМ. Плюс ссылки в блоге имеют заметную тенденцию к смерти 404 смерти. Пожалуйста, кратко изложите здесь свою статью или оставьте эту ссылку в комментарии к вопросу. Mat
Спасибо за упоминание аргумента -XX. Вы также можете использовать это, чтобы увидеть статистику таблицы: -XX: + PrintStringTableStatistics csadler
Спасибо, что написали это @ mik1! Очень информативная, понятная и актуальная статья. (Я вернулся сюда с намерением опубликовать ссылку на него.) Luke Usherwood
1

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

4

не упомянутые в Javadoc, то есть более или менее оптимизация JIT-компилятором?

Я не знаю об уровне JIT, но есть прямая поддержка байт-кода для пула строк, который реализован волшебно и эффективно с выделеннымCONSTANT_String_info struct (в отличие от большинства других объектов, которые имеют более общие представления).

JVMs

JVMS 7 5.1 говорит:

Строковый литерал является ссылкой на экземпляр класса String и является производным от структуры CONSTANT_String_info (§4.4.3) в двоичном представлении класса или интерфейса. Структура CONSTANT_String_info дает последовательность кодовых точек Unicode, составляющих строковый литерал.

Язык программирования Java требует, чтобы идентичные строковые литералы (то есть литералы, содержащие одинаковую последовательность кодовых точек) должны ссылаться на один и тот же экземпляр класса String (JLS §3.10.5). Кроме того, если метод String.intern вызывается для какой-либо строки, результатом является ссылка на тот же экземпляр класса, который будет возвращен, если эта строка появится в виде литерала. Таким образом, следующее выражение должно иметь значение true:

("a" + "b" + "c").intern() == "abc"

Чтобы получить строковый литерал, виртуальная машина Java проверяет последовательность кодовых точек, заданных структурой CONSTANT_String_info.

Если метод String.intern ранее вызывался для экземпляра класса String, содержащего последовательность кодовых точек Unicode, идентичную той, которая задана структурой CONSTANT_String_info, то результатом строкового литерала является ссылка на тот же экземпляр класса String .

В противном случае создается новый экземпляр класса String, содержащий последовательность кодовых точек Unicode, заданную структурой CONSTANT_String_info; ссылка на этот экземпляр класса является результатом строкового литерала. Наконец, вызывается метод intern нового экземпляра String.

Bytecode

Также поучительно взглянуть на реализацию байт-кода в OpenJDK 7.

Если мы декомпилируем:

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}

у нас есть постоянный пул:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc

а такжеmain:

 0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V

Обратите внимание:

0 а также3: то же самоеldc #2 константа загружена (литералы)12: создается новый экземпляр строки (с#2 как аргумент)35: a а такжеc сравниваются как обычные объекты сif_acmpne

Представление константных строк довольно волшебно в байт-коде:

у него есть специальный CONSTANT_String_info структура, в отличие от обычных объектов (например,new String) структура указывает на CONSTANT_Utf8_info Структура, который содержит данные. Это единственные необходимые данные для представления строки.

и приведенная выше цитата из JVMS, кажется, говорит, что всякий раз, когда Utf8, на который указывает ссылка, совпадает, идентичные экземпляры загружаются с помощьюldc.

Я провел аналогичные тесты для полей и:

static final String s = "abc" указывает на постоянную таблицу черезConstantValue Attribute неконечные поля не имеют этого атрибута, но все еще могут быть инициализированы с помощьюldc

Bonus: сравните это с Интегер пул, который не имеет прямой поддержки байт-кода (т.е. нетCONSTANT_String_info аналог).

Хорошее расследование! Daniel Rikowski
6

и если бы они были, можно было бы подумать, что equals () сама использовала бы intern () внутри (а это не так).

Разрушить стажеров () мифы

Также говорится, что общий относительный выигрыш, как правило, будет небольшим. objects
Несмотря на то, что вы говорите, что не знаете о каких-либо преимуществах, ваши опубликованные ссылки идентифицируют сравнение через == как 5-кратное ускорение и, следовательно, важное значение для текста-ориентированного кода исполнен Brian Agnew
Когда у вас будет много текста для сравнения, вам в конечном итоге не хватит места в PermGen. Когда для сравнения различий в тексте не так много разницы в скорости, это не имеет значения. В любом случае, просто не интернируйте () ваши строки. Это того не стоит. Bombe
Я не думаю, что такая логика верна. Хорошая ссылка, хотя! Daniel Rikowski
@ DR: какая логика? Это одна большая ошибка. @objects: извините, но ваши аргументы не соответствуют причинам. Естьочен веские причины использоватьintern и очень веские причины, по которымequals не делает этого по умолчанию. Ссылка, которую вы разместили, полная чушь. Последний абзац даже признает, чтоintern имеет допустимый сценарий использования: обработка тяжелого текста (например, анализатор). Заключить, что «[XYZ] опасно, если вы не знаете, что делаете», настолько банально, что это причиняет физический вред. Konrad Rudolph
0

которые ссылаются на связанные имена. Я интернирую строки в кеше, потому что многие коды указывают на одну и ту же строку.

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

Если интернированные строки были фактически собраны мусором, это не сработало бы для меня вообще. Это в основном сводит на нет цель интернирования. Мой не будет собирать мусор, потому что я держу ссылку на каждую строку в кэше.

Нет, все интернированные одинаковые строки, которые находятся в памяти в определенное время, все равно будут одним и тем же объектом. Это будет объект, отличный от той же строки, которая была в памяти перед сборкой мусора. Но это не проблема, потому что старой строки больше нет. bdruemen
4

String interning предназначен для экономии памяти (кучи). В нашей системе в настоящее время есть гигантская хэш-карта для хранения определенных данных. По мере масштабирования системы хэш-карта будет достаточно большой, чтобы создать кучу памяти (как мы уже тестировали). Путем интернирования всех дублированных строк всех объектов в хэш-карте это экономит нам значительный объем пространства кучи.

Также в Java 7, интернированные строки больше не живут в PermGen, а вместо этог Так что вам не нужно беспокоиться о его размере, и да, он получает мусор:

В JDK 7 интернированные строки больше не выделяются в постоянном поколении кучи Java, а вместо этого выделяются в основной части кучи Java (известной как молодое и старое поколения) вместе с другими объектами, созданными применение. Это изменение приведет к увеличению объема данных, находящихся в основной куче Java, и уменьшению объема данных в постоянной генерации, что может потребовать корректировки размеров кучи. Большинство приложений увидят только относительно небольшие различия в использовании кучи из-за этого изменения, но более крупные приложения, которые загружают много классов или интенсивно используют метод String.intern (), увидят более существенные различия.

Я должен подтвердить следующее: в моем программном обеспечении дамп кучи показал, что большая часть пространства кучи была использованаString экземпляры. Просматривая их содержание, я увидел много дубликатов и решил переключиться наintern(), что сэкономило сотни МБ. Matthieu
193

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

@ ArunRaaj нет, твои 1000 все еще в куче, и еще один в пуле стажеров, который может быть готов к повторному использованию позднееstr.intern() когдаstr является"Hello". Matthieu
Нужно уточнить - интернирование всегда происходит автоматически для константных строк времени компиляции (литералы и фиксированные выражения). Кроме того, это происходит, когда String.intern () вызывается во время выполнения динамически оцениваемых строк. Glen Best
это должен быть правильный принятый ответ ... Amit
Это не правильно. Интернирование строк происходит всегда, автоматически, когда оценивается каждое строковое выражение. Всегда есть одна копия для каждой уникальной строки используемых символов, и она «внутренне используется», если происходит многократное использование. Вызов String.intern () не делает все это возможным - он просто возвращает внутреннее каноническое представление. Смотрите Javadoc. Glen Best
То есть, если в Heap 1000 объектов «Hello» и я выполняю intern () для одного из них, остальные 999 объектов будут уничтожены автоматически? Arun Raaj
13

Сравнение строк с == намного быстрее, чем с equals ()

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

String.intern () вытащите строку из кучи и поместите ее в PermGen

нтернализованные строки @ помещаются в другую область хранения: Постоянное поколение которая является областью JVM, зарезервированной для не пользовательских объектов, таких как классы, методы и другие внутренние объекты JVM. Размер этой области ограничен и намного ценнее кучи. Поскольку эта область меньше, чем Heap, есть большая вероятность использовать все пространство и получить исключение OutOfMemoryException.

String.intern () строка - сборщик мусора

В новых версиях JVM внутренняя строка также собирается для мусора, когда на него не ссылается ни один объект.

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

Просто добавьте, исключения из памяти кучи иногда можно восстановить, особенно в многопоточных моделях, таких как веб-приложения. Когда permgen исчерпан, приложение, как правило, будет постоянно не функционировать и часто будет зависать до тех пор, пока не будет уничтожен Taylor
7

Учитывая, что они делают разные вещи, вероятно, никогда.

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

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

Почти всегда лучше создатьUserId type, который является интернированным (легко создать универсальный механизм интернирования, ориентированный на многопотоковое исполнение) и действует как открытое перечисление, чем при перегрузкеjava.lang.String введите со ссылочной семантикой, если это будет идентификатор пользователя.

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

2

subString() когда результат невелик по сравнению с исходной строкой, а объект имеет большую жизнь.

Нормальным решением является использованиеnew String( s.subString(...)) но когда у вас есть класс, в котором хранится результат потенциального / вероятногоsubString(...) и не имеет никакого контроля над вызывающим абонентом, вы можете хранитьintern() аргументов String, переданных конструктору. Это освобождает потенциально большой буфер.

Вышеупомянутая потенциальная утечка памяти не происходит в Java 1.8 и 1.7.06 (и новее), см. Изменяет строковое внутреннее представление в Java 1.7.0_06. eremmel
Это подтверждает, что микрооптимизации должны применяться только при необходимости после профилирования производительности и / или памяти. Спасибо akostadinov
Интересно, но, возможно, это зависит от реализации. akostadinov
2

String interning полезен в случае, когдаequals()етод @ часто вызывается, потому чequals()етод @ быстро проверяет, совпадают ли объекты в начале метод

if (this == anObject) {
    return true;
}

Это обычно происходит при поиске черезCollection хотя другой код также может проверять равенство строк.

За интернирование приходится платить, но я выполнил микробенчмарк некоторого кода и обнаружил, что процесс интернирования увеличивает время выполнения в 10 ра

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

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

Кроме того, нет смысла проводить интернирование в остальной части кода, поскольку это, как правило, не принесет никакой пользы.

0

использовать его после того, как вы получите ошибку нехватки памяти. Многие строки в типичной программе - это String.substring () другой большой строки [подумайте о том, чтобы извлечь имя пользователя из XML-файла размером 100 КБ. Реализация Java состоит в том, что подстрока содержит ссылку на исходную строку и начало + конец в этой огромной строке. (За этим стоит повторное использование одной и той же большой строки)

После 1000 больших файлов, из которых вы сохраняете только 1000 коротких имен, вы сохраняете в памяти все 1000 файлов! Решение: в этом случае просто используйте smallsubstring.intern ()

Почему бы не создать новую строку из подстроки, если она вам нужна? Thorbjørn Ravn Andersen
0

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

Так что есть альтернатива intern () для сокращения потребления памяти (для меня = = и равные преимущества в производительности не проблема)

0

основной сценарий использования - это когда вы читаете поток данных (либо через входной поток, либо из JDBC ResultSet), и существует множество маленьких строк, которые повторяются повсюду.

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

/**
 * Extends the notion of String.intern() to different mechanisms and
 * different types. For example, an implementation can use an
 * LRUCache<T,?>, or a WeakHashMap.
 */
public interface Internalizer<T> {
    public T get(T obj);
}
public static class LRUInternalizer<T> implements Internalizer<T> {
    private final LRUCache<T, T> cache;
    public LRUInternalizer(int size) {
        cache = new LRUCache<T, T>(size) {
            private static final long serialVersionUID = 1L;
            @Override
            protected T retrieve(T key) {
                return key;
            }
        };
    }
    @Override
    public T get(T obj) {
        return cache.get(obj);
    }
}
public class PermGenInternalizer implements Internalizer<String> {
    @Override
    public String get(String obj) {
        return obj.intern();
    }
}

Я часто использую это, когда читаю поля из потоков или из ResultSets. Заметка:LRUCache - это простой кеш, основанный наLinkedHashMap<K,V>. Он автоматически вызывает предоставленный пользователемretrieve() метод для всех промахов кэша.

Способ использовать это, чтобы создать одинLRUInternalizer перед чтением (или чтением) используйте его для усвоения строк и других небольших неизменяемых объектов, затем освободите его. Например

Internalizer<String> internalizer = new LRUInternalizer(2048);
// ... get some object "input" that stream fields
for (String s : input.nextField()) {
    s = internalizer.get(s);
    // store s...
}
0

чем время, сэкономленное при сравнении одной строки A.equals (B). Используйте его (из соображений производительности) только в том случае, если вы постоянно используете одни и те же неизменные строковые переменные. Например, если вы регулярно перебираете стабильный список строк для обновления некоторых карт, привязанных к одному и тому же строковому полю, вы можете получить хорошее сохранение.

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

Также помните, что String неизменны и не делают глупой ошибки

String a = SOME_RANDOM_VALUE
a.intern()

вспомни, чтобы сделать

String a = SOME_RANDOM_VALUE.intern()
0

а также для сборки мусора, то для меня хорошо работает следующее.

private static WeakHashMap<String, WeakReference<String>> internStrings = new WeakHashMap<>();
public static String internalize(String k) {
    synchronized (internStrings) {
        WeakReference<String> weakReference = internStrings.get(k);
        String v = weakReference != null ? weakReference.get() : null;
        if (v == null) {
            v = k;
            internStrings.put(v, new WeakReference<String>(v));
        }
        return v;
    }
}

Конечно, если вы можете приблизительно оценить, сколько будет различных строк, просто используйте String.intern () с -XX: StringTableSize = HighEnoughValue.

SoftRef будет больше смысла. vach
@ vach При использовании WeakReference (вместо SoftReference) память освобождается раньше, поэтому другие распределения могут выполняться быстрее. Это зависит от того, что еще делает приложение, может иметь смысл любой из них. bdruemen

Похожие вопросы