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

HttpClient.execute бросает OutOfMemoryError

У меня есть приложение для Android, которое отправляет JSONObject в качестве объекта с помощью объекта ByteArrayEntity. Вот как это выглядит:

post.setEntity(new ByteArrayEntity(entity.getBytes("UTF-8")));
result = client.execute(post, handler);

Сущность - это String. Обработчик ResponseHandler<String>, а клиент - HttpClient. Это хорошо работает на эмуляторе и на некоторых устройствах. Но иногда я получаю OutOfMemoryError при выполнении на x10i (также известной как XPERIA).

Вот стек:

java.lang.OutOfMemoryError
at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:79)
at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:93)
at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:171)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:580)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:678)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:652)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at com.test.application.api.Request.post(Request.java:102)
at com.test.application.api.API.getResult(API.java:123)
at com.test.application.api.APITask.doInBackground(APITask.java:127)
at com.test.application.api.APITask.doInBackground(APITask.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)

Как я уже сказал, я просто размещаю JSONObject как String. Это может быть не более 200 символов. Что не так?

4b9b3361

Ответ 1

У устройств Android есть предел для каждого процесса. Значение по умолчанию - 24 МБ, но некоторые устройства имеют меньшее значение, например, 16 МБ или, возможно, ниже. Похоже, что у X10i есть 384 МБ ОЗУ, что является низким для современного Android-устройства (теперь 1 ГБ стандартно), и это может создавать дополнительные ограничения.

Я бы предложил:

  • Сначала проверьте предел для каждого процесса на вашем устройстве. Используйте ActivityManager.getMemoryClass() для проверки.
  • Посмотрите на фактическое использование памяти, используя DDMS.

Вы можете обнаружить, что, как раз перед тем, как вы делаете этот вызов, вы уже находитесь на верхнем пределе памяти; инициализация HTTPClient и вызов могут привести вас к пределу. Это будет более вероятно, если OOM произойдет при первом вызове.

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

Ответ 2

В случае java.lang.OutOfMemoryError вероятно, что ваше приложение сохраняет ссылки на объекты, которые должны быть освобождены. Попробуйте отладить это приложение на этом телефоне, а не в эмуляторе.

Ответ 3

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

1) В случае сбоя выделяется более 200 байт (например, новый HttpClient выделяется для каждого вызова).

2) Этот код вызывается очень часто

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

Сколько раз эта строка кода была виновницей этой проблемы? Если ответа много, то 1) или 2) выглядят вполне вероятными. Поскольку у нас нет всего кода приложений, который трудно диагностировать, но обратите внимание на событие/обстоятельство, которое вызывает этот код, - он получает вызов от касания или перемещения - и если это так происходит каждый миллисекунда, как пользователь тянет их пальцем по экрану, потому что нет сна в цикле onTouch? Это то, что может варьироваться от платформы к платформе.

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