#java #android #memory #bitmap #garbage-collection
#java #Android #память #растровое изображение #сбор мусора
Вопрос:
Это кажется простой проблемой, но я не могу понять, что ее вызывает.
У меня есть одно действие, которое создает несколько растровых изображений с использованием Bitmap.CreateBitmap (ширина, высота, конфигурация), применяет к ним холст и рисует на холстах. Как только я закончу, я их утилизирую. Они создаются в том разрешении, в котором они отображаются, и не создают никаких проблем. В OnSurfaceDestroyed() я перерабатываю каждое растровое изображение. Как часть инструкций по рисованию, я выделяю временные растровые изображения, которые перерабатываются, как только они становятся ненужными. В качестве дополнительной меры я также помещаю System.gc() в OnSurfaceDestroyed() каждого действия.
Теперь, когда я переключаюсь между этим действием и другим действием (которое не создает растровых изображений), я получаю исключение OutOfMemoryException примерно через 6 или 7 переключений туда и обратно. LogCat дает понять, что каждый раз, когда я создаю первое действие, автоматический сборщик мусора освобождает все больше и больше места. Вот ошибка источника:
06-23 12:49:53.984: E/dalvikvm-heap(8487): Out of memory on a 1382416-byte allocation.
Я понимаю, что это огромное выделение байтов, но я не совсем понимаю, почему? Первые 5-6 раз проблем не возникает, так почему же память, похоже, накапливается, хотя я все перерабатываю? Я совершенно уверен, что больше я ничего не делаю с большим объемом памяти.
Я нашел обходной путь, используя Config.RGB_565 для создания растровых изображений вместо Config.ARGB_8888, но это просто увеличивает количество переходов назад и вперед до сбоя с 6-7 примерно до 30. По какой-то неизвестной причине память все еще накапливается.
Есть ли что-то другое, кроме recycle(), которое я могу использовать, или какой-либо другой системный ресурс, который мог бы помочь?
Ответ №1:
Первые 5-6 раз проблем не возникает, так почему же память, похоже, накапливается, хотя я все перерабатываю?
Он не накапливается. Он фрагментируется. На Java OutOfMemoryError
это довольно буквально: недостаточно места в куче для выделения нужного блока. На виртуальной машине Dalvik Android OutOfMemoryError
это действительно ThereIsNoBlockBigEnoughError
так, потому что у Dalvik нет сборщика компактного мусора. Я подробнее расскажу о том, что это значит (и на что должна повлиять новая среда выполнения ART) в сообщении в блоге.
Есть ли что-то другое, кроме recycle(), которое я могу использовать, или какой-либо другой системный ресурс, который мог бы помочь?
Шаг # 1: установите android:minSdkVersion
значение 11 или выше.
Шаг № 2: прекратите переработку ваших растровых изображений. Повторно используйте их, используя inBitmap
on BitmapFactory.Options
. Поддерживайте свой собственный пул доступных Bitmap
объектов, подлежащих переработке, для каждого требуемого разрешения изображения. Подробнее см. В этой части документации.
Комментарии:
1. Я попробую. Спасибо.
2. Я в основном понимаю, что происходит в этой документации, но есть только одна запутанная часть: я создаю растровые изображения программно, а не собираю их из файлов. В документации указано, что вы проходите через BitmapFactory, поскольку вам нужны параметры для получения inBitmap. Нужно ли сохранять мои растровые изображения в файл после их создания в первый раз, а затем извлекать их таким образом? Кажется ненужным шагом с того места, где я был. Мне никогда не приходилось использовать BitmapFactory в моем исходном процессе.
3. @JohnO.: «Я создаю растровые изображения программно, а не собираю их из файлов» — поскольку я не знаю точно, что это значит, вы можете отредактировать свой вопрос, чтобы объяснить, как вы их создаете и используете. Тем не менее, вы все равно сможете использовать их повторно, стирая их текущее содержимое и рисуя новое содержимое, а не отбрасывая и повторно создавая их экземпляры каждый раз.
4. Я создаю несколько растровых изображений, используя Bitmap.CreateBitmap (ширина, высота, конфигурация), применяю к ним холст и рисую на холстах. Как только я закончу, я их перерабатываю. Я буду продолжать просматривать документацию и ссылки, пока не найду способ заставить это работать.
5. @JohnO.: «Как только я закончу, я их переработаю» — повторно используйте их для другого случая, когда вам нужен
Bitmap
файл того же размера. ИспользуйтеeraseColor()
, чтобы стереть текущее содержимое (и установить желаемый фон), затем используйте aCanvas
для его повторного отображения. Толькоrecycle()
тогда, когда вы достаточно уверены, что вам не понадобится другой экземпляр aBitmap
с таким разрешением в течение значительного периода времени (а для больших разрешений, возможно, «значительный период времени» == «никогда»).