Подтвердить что ты не робот

Ошибка памяти в андроиде из-за увеличения размера кучи

Я выхожу из памяти. Я работаю над приложением в реальном времени. Он работает нормально, но когда я запускаю приложение от 1 до 2 часов на устройстве, размер кучи увеличивается, и когда он достигает значения в 16 МБ, приложение начинает висит и разбивается через некоторое время и показывает out of memory due to heap size, потому что результирующий размер кучи больше, чем выделено.

Я тестирую свое приложение на HTC Explorer. В моем приложении большинство действий использует фоновый поток, и для этого я использую Asnyc Task.

Я получаю ошибку, как показано ниже.

04-30 16:53:14.658: E/AndroidRuntime(5707): FATAL EXCEPTION: MagentoBackground
04-30 16:53:14.658: E/AndroidRuntime(5707): java.lang.OutOfMemoryError: (Heap Size=20167KB, Allocated=16063KB, Bitmap Size=355KB)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.util.ByteArrayBuffer.<init>(ByteArrayBuffer.java:53)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:82)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:98)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:173)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at com.live2support.CustomHttpClient.executeHttpPost1(CustomHttpClient.java:163)

Есть ли ограничение размера кучи? как я могу решить свою проблему?

4b9b3361

Ответ 1

Ваш вопрос состоит из двух частей:

1) Как определить размер кучи на моем тестовом устройстве?

2) Почему мое приложение превышает размер моей кучи?

Что касается вопроса 1, вы можете определить размер кучи на тестовом устройстве непосредственно в вашем коде, вызвав:

Runtime.getRuntime() maxMemory();.

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

Кроме того, если вы используете корневое устройство, может быть способ напрямую установить (и проверить) размер кучи через интерфейс. Например, в CyanogenMod различных версиях Android из меню "Настройки" вы можете выбрать "Настройки CyanogenMod", а затем "Производительность", а затем "Размер кучи VM" и непосредственно просмотреть (и изменить) размер кучи для вашего устройства, Будьте осторожны, так как установка слишком большого размера кучи может привести к неправильному функционированию вашего устройства или ухудшению.

В отношении вопроса 2: вы не предоставили достаточно информации для диагностики вашей конкретной проблемы, и в любом случае делать такой диагноз из вторых рук трудно в лучшем случае. Лучшим решением для решения этой проблемы (и для изучения чего-то длительного времени в процессе) должно стать ознакомление с некоторыми из очень мощных инструментов анализа памяти, доступных в Android (некоторые из которых также интегрированы в Eclipse IDE). Я использую эти инструменты из Eclipse, поэтому я опишу ниже.

Прежде всего, убедитесь, что версия Eclipse обновлена, установив последнюю версию Eclipse (например, Indigo).

Затем в Eclipse выберите "Справка/Установить новое программное обеспечение", а затем нажмите раскрывающееся меню вверху и выберите

"Indigo - http://download.eclipse.org/releases/indigo"

Затем откройте категорию "Инструменты общего назначения", щелкнув рядом с ним знак "плюс" и выберите "Анализатор памяти", а также "Анализатор памяти" ( "Графики" ) [необязательно]. Установите эти инструменты.

Затем выберите Window/Preferences, а затем Android/DDMS и выберите действие HPROF как "Открыть в Eclipse". Это приведет к тому, что любой файл дампа HPROF, который вы создаете из DDMS, будет иметь соответствующий формат для Eclipse, а также приведет к его автоматическому открытию в Eclipse Memory Analyzer (который был только что установлен выше).

Теперь откройте DDMS, выбрав Window/Open Perspective/Other/DDMS. Выберите значок "Устройства" (выглядит как телефон) слева и перетащите результирующее окно так, чтобы оно было состыковано где-нибудь, где вы можете легко его увидеть.

Убедитесь, что ваше устройство подключено к ПК через USB и работает ваше приложение.

На вкладке "Устройства" , которую вы только что создали, выберите выполняемый процесс приложения. Запустите приложение до того места, где он занял достаточно памяти, что, как вы знаете, он просочился, но не настолько, что он сбой. Теперь щелкните значок Dump HPROF File на вкладке "Устройства" . После небольшой задержки вам будет предложен выбор отчетов на вашей куче. Попробуйте отчет о подозрениях на утечку, чтобы начать работу. Этот отчет откроется в инструменте анализа памяти. Он сообщает вам, где ваше приложение использует память. Проверьте различные типы объектов и посмотрите, выглядят ли они раздутыми относительно количества данных, которые вы ожидаете от них; если это так, это может означать утечку.

Здесь - это хороший учебник, в котором более подробно описывается, как генерировать и исследовать вашу кучу, используя DDMS и инструмент анализатора памяти.

Назад в DDMS (или перспектива DDMS в Eclipse), вы можете выбрать вкладку Allocation Tracker, когда ваше устройство подключено, а затем ваше устройство со вкладки устройств, а затем выберите процесс вашего приложения из списка для этого устройства. Затем на вкладке Allocation Tracker нажмите кнопку "Начать отслеживание", а затем запустите соответствующие действия приложения (те, которые вы подозреваете, протекают), а затем нажмите кнопку "Получить выделение", а затем нажмите кнопку "Отключить отслеживание".

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

Эти инструменты должны дать вам некоторое представление о том, что может вызвать у вас утечку памяти.

Ответ 2

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

Первое, что я вам рекомендую: http://www.youtube.com/watch?v=_CruQY55HOk

Чтобы проверить, есть ли у вас такая утечка памяти, поверните устройство и проверьте, как ведет себя сборщик мусора. Вы должны иметь что-то вроде GC_... freed 211K, 71% free 300K/1024K, external 0K/0K, paused 1ms+1ms в своем LogCat почти каждый раз, когда вы вращаетесь. Следите за изменениями в этой части: 300K/1024K. Если у вас нет утечек памяти, первая часть должна расти, а затем уменьшаться после нескольких GC. Если у вас есть утечка памяти, она будет расти и расти, вплоть до ошибки OOM.

Если вы убедитесь, что у вас есть утечка памяти таким образом, вам нужно установить MAT для Eclipse, узнать, как его использовать (с вышеупомянутым фильмом) и узнать, что он вызывает.

Моя личная ставка будет плохой реализацией AsyncTask - вы отделите ее от уничтоженной активности и прикрепите ее к новой? Если нет, начните делать это (там есть отличный пример от CommonsWare) или переключитесь на AsyncTaskLoader, который сделает это за вас, и обычно это отличная замена для AsyncTask (не только для загрузки файлов).

Ответ 3

Просто добавьте android:largeHeap="true" в тег приложения в свои манифесты.

Ответ 4

Ограничение размера кучи зависит от устройства. На устройстве 2.x я ожидаю, что около 20 или 32 МБ - ваш лимит. Более подробную информацию о размерах кучи см. В разделе Размер кучи Android на разных телефонах/устройствах и версиях ОС.

Из вашей трассировки стека, похоже, что com.live2support.CustomHttpClient.executeHttpPost1() находится в центре вашей проблемы.

Ответ 5

Это можно сделать двумя способами в соответствии с вашей ОС Android.

  • Вы можете использовать android:largeHeap="true" в теге приложения манифеста Android, чтобы запросить больший размер кучи, но это не будет работать на каких-либо устройствах предварительной сотовой связи.
  • На устройствах версии 2.3 вы можете использовать класс VMRuntime, но это не будет работать на Gingerbread и выше. См. ниже, как это сделать.
VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE);

Перед настройкой HeapSize убедитесь, что вы ввели соответствующий размер, который не повлияет на работу другого приложения или ОС. Перед установкой достаточно проверить размер вашего приложения, а затем установить размер только для выполнения вашей работы. Не используйте так много памяти, иначе могут повлиять другие приложения.

Ссылка: http://dwij.co.in/increase-heap-size-of-android-application