Повторное использование растрового изображения в методе финализации не работает должным образом
У меня возникают сбои в приложении, когда я пытаюсь загрузить изображение с размером, близким к максимальному размеру кучи приложения. В первый раз, когда я загружаю изображение, все в порядке, затем я удаляю ссылки на объект Bitmap и вызывается его финализация, где я вызываю mBitmap.recycle() //nativeRecycle. Очевидно использование памяти уменьшается, но когда я пытаюсь загрузить изображение снова, я получаю сбой OutOfMemory. Интересно то, что если я вызываю recycle только в том же классе, где удаляю ссылки, создается впечатление, что память освобождена, и я могу снова загрузить изображение. Таким образом, в основном я получаю другие результаты, если я вызываю напрямую mBitmap.recycle (), чем если бы я поместил mBitmap.recycle () в финализацию объекта, ссылающегося на растровое изображение. Есть идеи, почему это происходит?
1 ответ
Если вы настолько близки к использованию максимального размера кучи, возможно, вам просто повезло (или не повезло). Вызов recycle() напрямую вместо вызова из финализатора может изменить время и поведение GC таким образом, что вы увидите различия.
Вы уверены, что ваш финализатор (и recycle()) вызывается до того, как вы попытаетесь перераспределить растровое изображение? Финализаторы ненадежны и могут быть отложены на неопределенный срок. Даже если вы видите, что финализатор вызывается перед перераспределением во время тестирования, нет гарантии, что это всегда будет происходить (особенно для разных состояний кучи или будущих / разных версий Dalvik).
Если вы можете, постарайтесь как можно больше вызвать recycle() из-за пределов финализатора. Если вы знаете, когда закончите, просто вызовите метод; в противном случае рассмотрите возможность использования ReferenceQueue ( /questions/39340767/ispolzovanie-referencequeue-i-weakreference/39340778#39340778).
Прошло довольно много времени с тех пор, как я посмотрел на Dalvik, но, похоже, я помню, что буферы растровых изображений могут очищаться за несколько циклов GC, потому что виртуальная машина должна быть уверена, что ни у одного нативного кода не осталось никаких указателей. Таким образом, буфер не может быть освобожден именно тогда, когда вы ожидаете, что он будет.
Также существует вероятность того, что фрагментация кучи вызывает проблемы, хотя есть большая вероятность, что большие буферы выделяются с помощью mmap() и не будут способствовать фрагментации (опять же, в зависимости от текущей версии Dalvik).