Сборщик мусора в Android

108

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

Является ли хорошей практикой запрашивать сборщик мусора в Android перед выполнением операции, требующей большого количества памяти? Если нет, следует ли мне вызывать его только в случае OutOfMemoryошибки?

Есть ли другие вещи, которые мне следует использовать, прежде чем прибегать к сборщику мусора?

hpique
источник

Ответы:

144

Для версий до 3.0 сота : Да, звоните System.gc() .

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

При создании растровых изображений Android часто дает сбой из-за ошибок нехватки памяти и не пытается сначала выполнить сборку мусора . Следовательно, вызовите System.gc(), и у вас будет достаточно памяти для создания растровых изображений.

При создании объектов, я думаю, System.gcон будет вызываться автоматически при необходимости, но не для создания растровых изображений. Это просто не удается.

Поэтому я рекомендую вызывать вручную System.gc()перед созданием растровых изображений.

Стив
источник
39
Это связано с тем, что данные растрового изображения до соты не хранятся в виртуальной машине и не запускают сборщик мусора. Это не должно быть проблемой в Honeycomb и более поздних версиях.
Тимммм
2
@Timmmm, но на самом деле это была моя проблема, я просто установил для largeheap значение true.
Лей Лейба
118

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

Иногда , в некоторых относительно редких ситуациях, можно обнаружить, что конкретный сборщик мусора ошибается, и ручной вызов сборщика мусора может улучшить ситуацию с точки зрения производительности. Это потому, что на самом деле невозможно реализовать «идеальный» сборщик мусора, который бы оптимально управлял памятью во всех случаях. Такие ситуации трудно предсказать и зависят от многих тонких деталей реализации. «Хорошая практика» - позволить сборщику мусора работать сам по себе; ручной вызов GC является исключением, которое следует предусмотреть только после того, как будет должным образом засвидетельствована реальная проблема производительности.

Томас Порнин
источник
8
+1 за хороший платформо-независимый ответ. Жду, чтобы увидеть, придумает ли кто-нибудь конкретный ответ для Android, прежде чем сделать выбор.
hpique
8
Я согласен с тем, что вы написали, если вы позволяете «производительности» означать нечто более общее, чем эффективность процессора. На устройстве Android первостепенное значение имеет восприятие пользователем производительности. Разработчик может предпочесть запускать GC, когда пользователь, например, нажимает кнопки, поэтому пользователь не будет знать о GC.
Президент Джеймс К. Полк,
5
В играх часто важно, чтобы сборщик мусора не запускался во время работы игры (для этого необходимо, чтобы все объекты были предварительно созданы, переработаны или аналогичны), но когда игра приостановлена, самое время для сборки мусора.
Пэт
4
Предварительно соты, растровые данные не хранятся в памяти виртуальной машины. Система не обнаружит, когда вы использовали слишком много памяти, не относящейся к виртуальной машине, из-за растровых изображений и запустит сборщик мусора (который запустит Bitmap.finalize()методы, освобождающие память, не относящуюся к виртуальной машине). Следовательно, в этом случае вы должны перейти через голову GC и запустить Bitmap.recycle()или, System.gc()где это необходимо. Но только предварительно соты.
Timmmm
1
@ThomasPornin - С другой стороны, как программист приложения, вы знаете кое-что, чего не знает ОС: время, в которое ваше приложение теперь будет вносить серьезные изменения в то, как оно использует память, и что это будет менее разрушительно для пользовательский опыт должен сделать паузу сейчас, а не в произвольный момент в будущем . Это означает, что может быть разумным совершать нечастые вызовы во время основных переходов в использовании приложения. Они редки в том смысле, что не следует часто вызывать сборщик мусора, но обычны в том смысле, что почти в любом значительном приложении есть такие заведомо известные моменты.
ToolmakerSteve
26

Недостаточно памяти в приложении Android очень часто, если мы не обрабатываем растровое изображение должным образом. Решением проблемы может быть

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

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

Если проблема все еще возникает, вы также можете добавить эту строку

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

для получения дополнительной информации перейдите по этой ссылке

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


ПРИМЕЧАНИЕ. Из-за кратковременной «паузы», вызванной выполнением gc, не рекомендуется делать это перед каждым выделением битовой карты.

Оптимальный дизайн - это:

  1. Освободите все растровые изображения, которые больше не нужны , с помощью if / recycle / nullпоказанного кода. (Придумайте способ, который поможет с этим.)

  2. System.gc();

  3. Разместите новые растровые изображения.

йогеш
источник
19

Если вы получаете OutOfMemoryError, то обычно уже слишком поздно вызывать сборщик мусора ...

Вот цитата разработчика Android:

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

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

Андреас Долк
источник
6
Нельзя ли интерпретировать цитату иначе? Возможно, сборщик мусора необходимо вызвать вручную, чтобы собрать эти объекты до того, как они потребят слишком много памяти.
hpique
@hgpc: Я не понимаю, как цитату можно интерпретировать так, как вы предлагаете. Я предполагаю, что документация - это признание, признание того, что их сборщик мусора прост; при нехватке памяти выполняется полный сборщик мусора.
Президент Джеймс К. Полк,
Полноценное использование сложных объектов и фреймворков, использующих сложные объекты, позволяет лучше использовать время разработки, чем преждевременная оптимизация. Беспокойство об оптимизации - это более легкая ловушка для Android, чем для Enterprise Java, поскольку мы подсознательно продолжаем думать о производительности при кодировании мобильного приложения. Тем более, что разработчики фреймворка, которым приходится думать о производительности, пропускают эту точку зрения в свою официальную документацию, когда не проявляют осторожности.
LateralFractal
9

Вроде System.gc()не работают на Art Android 6.0.1 Nexus 5x, поэтому пользуюсь Runtime.getRuntime().gc();взамен.

cmicat
источник
1
System.gc()это функция-оболочка для Runtime.getRuntime().gc(). См. Android.googlesource.com/platform/libcore/+/…
Натан Ф.
Да, из исходников и документации похоже, что они одинаковы, но на самом деле System.gc()у меня это не работает, но Runtime.getRuntime().gc()работает!
Иван
7

Мое приложение управляет множеством изображений, и оно умерло с ошибкой OutOfMemoryError. Это мне помогло. В Manifest.xml Добавить

<application
....
   android:largeHeap="true"> 
Klykoo
источник
9
Google это не нравится
Педро Пауло Аморим
1
@PedroPauloAmorim объясните почему?
Machado
2
Не используйте largeHeap, если вы не уверены, что делаете. Использование больших куч усложняет работу сборщика мусора, потому что ему приходится перебирать множество ненужных данных, прежде чем очистить память.
Prakash
7

Вообще говоря, вы не должны явно вызывать GC с помощью System.gc (). Есть даже лекция по вводу-выводу ( http://www.youtube.com/watch?v=_CruQY55HOk ), где они объясняют, что означает журнал пауз сборщика мусора и в котором также говорится, что никогда не следует вызывать System.gc (), потому что Dalvik знает лучше чем вы, когда это сделать.

С другой стороны, как упоминалось в ответах выше, уже процесс GC в Android (как и все остальное) иногда бывает ошибочным. Это означает, что алгоритмы Dalvik GC не соответствуют JVM Hotspot или JRockit и в некоторых случаях могут работать неправильно. Один из таких случаев - при выделении растровых объектов. Это сложно, потому что он использует память кучи и не кучу, и потому что одного свободного экземпляра объекта растрового изображения на устройстве с ограничением памяти достаточно, чтобы вызвать исключение OutOfMemory. Поэтому вызов его после того, как вам больше не нужно это растровое изображение, обычно предлагают многие разработчики, а некоторые даже считают хорошей практикой.

Лучше использовать .recycle () для растрового изображения, поскольку для этого и создан этот метод, поскольку он отмечает внутреннюю память растрового изображения как безопасную для удаления. Имейте в виду, что это очень зависит от версии, что означает, что это обычно требуется в более старых версиях Android (я думаю, до 3.0), но не потребуется в более поздних версиях. Также не повредит его использование в более новых версиях эфира (только не делайте этого в цикле или что-то в этом роде). Новая среда исполнения ART здесь сильно изменилась, потому что они представили специальный «раздел» кучи для больших объектов, но я думаю, что это не повредит, если сделать это с помощью ART ether.

Также одно очень важное замечание о System.gc (). Этот метод не является командой, на которую Dalvik (или JVM) обязан отвечать. Считайте, что это больше похоже на обращение к виртуальной машине: «Не могли бы вы сделать сборку мусора, если это не мешает».

Игорь Кордаш
источник
3

Я бы сказал нет, потому что разработчик документирует состояние использования ОЗУ :

...
GC_EXPLICIT

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

...

Я выделил соответствующую часть жирным шрифтом.

Взгляните на серию YouTube « Паттерны производительности Android» - в ней вы найдете советы по управлению использованием памяти вашим приложением (например, использование ArrayMaps и SparseArrays вместо HashMaps в Android ).

Фарбод Саламат-Заде
источник
3

Краткое примечание для разработчиков Xamarin .

Если вы хотите позвонить System.gc()в приложения Xamarin.Android, вы должны позвонитьJava.Lang.JavaSystem.Gc()

Денис Гордин
источник
2

Нет необходимости вызывать сборщик мусора после файла OutOfMemoryError.

В Javadoc четко сказано:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

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

пердиан
источник
8
Документ Android Javadoc не утверждает этого, и, скорее всего, его реализация отличается. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique
Вы правы, что это не относится к Android. Но опять же, вы не можете обрабатывать OOE во время выполнения эфира, поэтому вы не можете много с этим поделать, даже если это было / не было правдой.
Игорь Кордаш