Intereting Posts
Android NDK / JNI – неопределенная ссылка на функцию, определенную в пользовательском файле заголовка Gradle: Как запустить пользовательскую задачу после создания библиотеки Android? Multi Выберите <select> на мобильных устройствах Использование библиотеки ViewPagerIndicator с Android Studio и Gradle Диалоговое окно тестирования в ActivityUnitTestCase от Android GCM / FCM: не принимать события, трансляция вызова вызова: result = CANCELED Как добавить теневой эффект на выделение в android I / art: Не удается найти класс: Смутно о различиях AdMob, Ad Exchange и DFP PhoneGap Disable Screen Rotate On Single Page? Ошибки вычисления значения двойной точности на процессорах MediaTek Каким должен быть JID для пользователя на OpenFire Server? Android – переход на активность без перезагрузки Переключение на определенный фрагмент дает странное java.lang.NullPointerException Как получить непрерывное событие mousemove при использовании мобильного браузера Android?

Фрагментация памяти GC GC не выполняется. Обходной путь?

Я тестирую версию android 3.1, большой вариант с утилизацией, около 250 миллионов памяти.

Я устанавливаю следующий код для запуска, когда я нажимаю кнопку «Тест» в привилегиях моего приложения:

float [][][]foo = new float[3][2048][2048]; Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888); bm.recycle(); bm = null; foo = null; 

У меня много памяти для этого – я могу нажать кнопку несколько раз без проблем.

Но если я продолжаю нажимать кнопку, в конечном итоге (менее 20 ударов), она умирает с OutOfMemory. [Обычно в android.graphics.Bitmap.nativeCreate (собственный метод)]

Больше ничего не происходит – мне никогда не придется покидать PreferencesActivity. Существует небольшой Toast, который также отображается, когда я нажимаю кнопку, так что крошечное количество других действий пользовательского интерфейса происходит.

Это связано с фрагментацией или просто ужасной ошибкой в ​​коде Bitmap android и / или GC? Или я просто делаю что-то глупое? (Пожалуйста, пусть это будет что-то глупое …)

У кого-нибудь есть обходной путь? Поскольку приведенное выше является достаточно представительным, что мой код должен делать каждый раз, когда пользователь вызывает его, и сейчас, несмотря на тщательную очистку переменных, он умирает после нескольких применений. (И это уже давно задирает меня!)

[Обновить]

Я подтвердил, что это проблема фрагментации или ошибка gc, поскольку дамп кучи показывает, что я использую только 5.6M, когда простой (без утечек) достигает максимума около 26M во время обработки. (Кроме того, нативная куча остается ниже 4M.) Пока куча java тем временем растет в пределах вплоть до предела 280M на моем тестовом устройстве, в котором я начинаю получать исключения OutOfMemory. Поэтому я использую только 10% моей кучи на пике, но получаю OutOfMemory.

[Добавление вызова в System.gc (), к сожалению, устраняет простой тестовый пример, который я приводил выше. Я говорю неудачно, потому что (A) это не должно меняться, и (B), потому что я уже регулярно нахожу его в своем реальном коде, поэтому это означает, что мой простой пример теста слишком прост.]

Кто-нибудь еще сталкивается с этим? Любые обходные пути? Есть ли изящный способ перезапустить мое приложение?

[Обновить]

Следующая версия надежно вызывает OutOfMemory в 3-4 вызовах (нажатия кнопки):

 float [][][]foo = new float[3][2048][2048]; Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888); int []bar = new int[3*2048*2048]; bm.recycle(); bm = null; System.gc(); foo = null; System.gc(); bar = null; System.gc(); 

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

Я бы сказал, что это проблема фрагментации, а не ошибка gc как таковая. Если кто-нибудь знает, как это исправить, дайте мне знать. Распределение int [] предназначено для написания растрового изображения, поэтому у меня нет возможности выделить его как массив 2d (ограничение библиотеки Bitmap андроида).

Solutions Collecting From Web of "Фрагментация памяти GC GC не выполняется. Обходной путь?"

Вот еще одна страница SO, которая, видимо, имеет обходной путь для этой проблемы:

Странная проблема с памятью при загрузке изображения в объект Bitmap

В частности, ответ Эфраим (выдержка):

«1) Каждый раз, когда вы выполняете BitmapFactory.decodeXYZ (), обязательно передавайте в BitmapFactory.Options с inPurgeable, установленным в true (и предпочтительно с inInputShareable также установлено значение true).

«2) НИКОГДА не используйте Bitmap.createBitmap (ширина, высота, Config.ARGB_8888). Я имею в виду НИКОГДА! У меня никогда не было этой вещи, которая не вызывала ошибку памяти после нескольких проходов. Никакого количества recycle (), System.gc (), Независимо от того, что помогло.Это всегда возникало исключение.Один другой способ, который на самом деле работает, состоит в том, чтобы иметь фиктивный образ в ваших чертежах (или другом растровом изображении, который вы декодировали с помощью шага 1 выше), масштабировать его до того, что вы хотите, а затем манипулировать полученным Bitmap ( Например, передавать его на холст для удовольствия) .Так что вы должны использовать вместо этого: Bitmap.createScaledBitmap (srcBitmap, width, height, false). Если по какой-либо причине вы ДОЛЖНЫ использовать метод создания грубой силы, Наименьший проход Config.ARGB_4444. "

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

Я бы добавил, что Diane Hackborn прокомментировала, что с 3.0 Android больше не выделяет растровые изображения из родной кучи, а вместо этого напрямую выделяет их из обычной кучи. Это может привести к тому, что ваши родные фигуры кучи не имеют значения. См. Комментарий hackbod на этой странице:

Растровые изображения на Android

Я предполагаю, что это подразумевает довольно существенное изменение, как Honeycomb относительно распределения битмапа, и поэтому может объяснить, почему есть ошибки с такими выделениями (если есть). Я не знаю, какое влияние это изменение оказывает на команду recycle (), но в свете вышеприведенных комментариев Эфраим ответ может быть «не очень хорошим».

В заключение,

Чтобы использовать largeHeap для глотания огромных растровых изображений, можно увидеть, что вы не играете хорошо с другими приложениями, особенно если вы приближаетесь к физическим пределам устройства. Я не уверен, как вы можете этого избежать, но будьте готовы к большому количеству операций onPause () / onResume (), поскольку ваши действия приложений в других приложениях, и они отступают от вас. Этот ответ SO включает в себя обсуждение этого:

Определить размер кучи приложения в Android

Чтобы предотвратить фрагментацию, вы можете просто выделить большой массив AND Bitmap один раз и повторно использовать его.

Для Android есть некоторые предостережения, так как Android пытается в какой-то степени управлять ресурсами вашего приложения. Например, Activity или View могут быть выгружены, если они не видны, и повторно запустите позже, если они снова станут видимыми. Поэтому большие вещи лучше хранить на объекте Application или static месте.

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

Существует очень подробная статья об управлении растровой памятью на android developers.android.com:

http://developer.android.com/training/displaying-bitmaps/manage-memory.html

В основном они рекомендуют использовать Bitmap.recycle (), чтобы избежать ошибок OutOfMemoryError для Android 2.3.3 и ниже. Согласно документации, он освобождает собственный объект, связанный с объектом Bitmap.