Управление строками и памятью

Я с трудом пытаюсь понять, что происходит с Strings и управлением памятью в Android (Java).

Чтобы упростить, посмотрите на этот простой фрагмент кода:

public void createArray(){ String s = ""; String foo = "foo"; String lorem = "Lorem ipsum ad his scripta blandit partiendo, eum fastidii accumsan euripidis in, eum liber hendrerit an."; ArrayList<Item> array = new ArrayList<Item>(); for( int i=0; i<20000; i++ ){ s = foo.replace("foo", lorem); array.add( new Item(s) ); } System.gc(); } private class Item{ String name; public Item(String name){ this.name = name; } } 

Если выполнено, createArray будет выделять более 5 Мб в памяти. Даже с помощью команды System.gc() память не будет освобождена после цикла.

Теперь, если мы заменим s = foo.replace("foo", lorem); С s = lorem; , Выделенная память будет увеличиваться только на 0,5 Мб.

Мне нужно понять, что происходит, чтобы улучшить производительность моего приложения.

Может ли кто-нибудь объяснить, как заменить строки в таком случае? И почему System.gc() не освобождает память?

Благодарю.

ОБНОВЛЕНИЕ :

Спасибо за ответы, теперь я понимаю, что System.gc() – это всего лишь намек.

Чтобы прояснить другой вопрос (важный):

Как я могу динамически генерировать строки 20000 («foo1», «foo2» … «foo20000») добавить их в ArrayList и не исчерпывать память? Если эти 20000 строк были статическими, они не выделяли бы более 0,5 Мб в памяти. Кроме того, если s = foo.replace("foo", lorem) создает совершенно новую String, почему моя функция выделяет 5Mb, которая в 10 раз больше памяти? Не должно быть около 1 Мб?

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

Solutions Collecting From Web of "Управление строками и памятью"

replace генерирует новый объект String каждый раз, когда он вызывается, поскольку строки в Java неизменяемы и поэтому модификации не могут быть сделаны «не-место». Кроме того, вы добавляете String в ArrayList который будет содержать ссылку на новый объект, не позволяя ему собираться.

Поскольку String неизменяемы, вызов foo.replace("foo", lorem) будет создавать новую String каждый раз. В примере, где вы просто устанавливаете s = lorem , не s = lorem новая String .

Кроме того, System.gc () является просто рекомендацией для виртуальной машины, и она никоим образом не гарантирует сбор мусора. Вы ничего не можете сделать, чтобы заставить сбор мусора. (Кроме использования всей доступной памяти)

System.gc () – это подсказка к сборщику мусора для повторного запуска, когда у него есть время.

Тем не менее сборщик мусора собирает только объекты без ссылок, и все строки, которые вы создали, все еще удерживаются array объектов. Вполне возможно, что вы можете добавить строки после System.gc()

 for (String item : array) { System.out.println(item); } 

Это доказало бы мудрость сборщика мусора, не разрушая струны.

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

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

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

Имейте в виду, что System.gc() не приводит к запуску сборщика мусора. Это всего лишь намек на то, что вы хотите, чтобы он запускался в какой-то момент в будущем.