Скажем, я использовал переменную с большим количеством данных String data
. Я хотел использовать небольшую часть этой строки следующим образом:
this.smallpart = data.substring(12,18);
После нескольких часов отладки (с визуализатором памяти) я обнаружил, что поле объектов smallpart
запоминает все данные data
, хотя оно содержит только подстроку.
Когда я изменил код на:
this.smallpart = data.substring(12,18)+"";
... проблема была решена! Теперь мое приложение использует очень мало памяти!
Как это возможно? Кто-нибудь может объяснить это? Я думаю, что this.smallpart продолжал ссылаться на данные, но почему?
ОБНОВЛЕНИЕ: Как я могу очистить большую строку тогда? Будет ли data = new String (data.substring (0,100)) действовать?
java
performance
string
memory
hsmit
источник
источник
new String(String)
; см. stackoverflow.com/a/390854/8946 .Ответы:
Делать следующее:
создает новый (меньший) объект String и выбрасывает ссылку на строку, созданную substring (), что позволяет собирать мусор.
Важно понять, что это
substring()
дает окно на существующую строку, или, вернее, массив символов, лежащий в основе исходной строки. Следовательно, он будет использовать ту же память, что и исходная строка. Это может быть выгодно в некоторых обстоятельствах, но проблематично, если вы хотите получить подстроку и удалить исходную строку (как вы узнали).Посмотрите на метод substring () в источнике JDK String для получения дополнительной информации.
РЕДАКТИРОВАТЬ: Чтобы ответить на ваш дополнительный вопрос, создание новой строки из подстроки уменьшит потребление памяти при условии, что вы удалите все ссылки на исходную строку.
ПРИМЕЧАНИЕ (январь 2013 г.) Вышеупомянутое поведение изменилось в Java 7u6 . Шаблон flyweight больше не используется и
substring()
будет работать так, как вы ожидаете.источник
String(String)
конструктор (т.е. конструктор String, принимающий String в качестве входных данных) полезен:new String(data.substring(x, y))
фактически делает то же самое, что и добавление""
, но делает намерение несколько более ясным.value
атрибут исходной строки. Я думаю, поэтому ссылка сохраняется.Если вы посмотрите на источник
substring(int, int)
, вы увидите, что он возвращает:где
value
находится оригиналchar[]
. Таким образом, вы получите новую строку, но с тем же основнымchar[]
.Когда вы это сделаете,
data.substring() + ""
вы получите новую строку с новым базовымchar[]
.На самом деле, ваш вариант использования - единственная ситуация, когда вы должны использовать
String(String)
конструктор:источник
new String(String)
; см. stackoverflow.com/a/390854/8946 .Когда вы используете
substring
, он фактически не создает новую строку. Он по-прежнему относится к вашей исходной строке с ограничением смещения и размера.Итак, чтобы позволить вашей исходной строке быть собранной, вам нужно создать новую строку (используя
new String
, или что у вас есть).источник
Поскольку строки Java состоят из массива char, начального смещения и длины (и кэшированного hashCode). Некоторые операции String, такие как
substring()
создание нового объекта String, который разделяет массив char оригинала и просто имеет различные поля смещения и / или длины. Это работает, потому что массив char String никогда не изменяется после его создания.Это может сэкономить память, когда многие подстроки ссылаются на одну и ту же базовую строку без репликации перекрывающихся частей. Как вы заметили, в некоторых ситуациях он может защитить ненужные данные от сбора мусора.
«Правильный» способ исправить это
new String(String)
конструктор, т.е.Кстати, в целом лучшим решением было бы избегать, во-первых, иметь очень большие строки и обрабатывать любые входные данные небольшими порциями по несколько КБ за раз.
источник
new String(String)
; см. stackoverflow.com/a/390854/8946 .В Java строки являются неизменяемыми объектами, и как только строка создается, она остается в памяти до тех пор, пока не будет очищена сборщиком мусора (и эту очистку нельзя воспринимать как должное).
Когда вы вызываете метод подстроки, Java не создает полностью новую строку, а просто сохраняет диапазон символов внутри исходной строки.
Итак, когда вы создали новую строку с этим кодом:
вы фактически создали новую строку, когда объединили результат с пустой строкой. Поэтому.
источник
Как документально подтверждено JWZ в 1997 году :
источник
Подводя итог, если вы создаете много подстрок из небольшого количества больших строк, тогда используйте
Так как вы используете пространство только для хранения больших строк, но если вы извлекаете всего несколько маленьких строк из потери больших строк, то
Сохранит использование памяти, поскольку большие строки могут быть восстановлены, когда они больше не нужны.
То, что вы называете,
new String
является полезным напоминанием о том, что вы действительно получаете новую строку, а не ссылку на исходную.источник
new String(String)
; см. stackoverflow.com/a/390854/8946 .Во-первых, вызов
java.lang.String.substring
создает новое окно на оригиналеString
с использованием смещения и длины вместо копирования значительной части базового массива.Если мы поближе познакомимся с
substring
методом, мы заметим вызов конструктора строкиString(int, int, char[])
и передачу его целиком,char[]
который представляет строку . Это означает, что подстрока будет занимать столько же памяти, сколько и исходная строка. .Хорошо, но почему это
+ ""
приводит к тому, что требуется меньше памяти, чем без нее?Выполнение
+
ONstrings
осуществляется с помощьюStringBuilder.append
вызова метода. Посмотрите на реализацию этого метода вAbstractStringBuilder
классе, и мы расскажем, что он наконец-то делаетarraycopy
с той частью, которая нам действительно нужна (substring
).Любой другой обходной путь ??
источник
Добавление "" к строке иногда экономит память.
Допустим, у меня есть огромная строка, содержащая целую книгу, миллион символов.
Затем я создаю 20 строк, содержащих главы книги в качестве подстрок.
Затем я создаю 1000 строк, содержащих все абзацы.
Затем я создаю 10000 строк, содержащих все предложения.
Затем я создаю 100 000 строк, содержащих все слова.
Я до сих пор использую только 1 000 000 символов. Если вы добавите «» к каждой главе, абзацу, предложению и слову, вы используете 5 000 000 символов.
Конечно, это совсем другое дело, если вы извлекаете только одно слово из всей книги, и вся книга может быть собрана мусором, но не потому, что это слово содержит ссылку на него.
И опять же, если у вас есть строка из одного миллиона символов и вы убираете табуляцию и пробелы на обоих концах, скажем, 10 вызовов для создания подстроки. То, как работает или работает Java, позволяет избежать копирования миллиона символов каждый раз. Есть компромисс, и хорошо, если вы знаете, что это за компромиссы.
источник