Потоки и службы Android останавливаются без предварительного уведомления

Итак, я сделал приложение, которое использует много потоков/Runnable (мы говорим о 300+) для загрузки большого количества контента. Это отлично работает на эмуляторе и некоторых устройствах, таких как Samsung Galaxy S3, но по какой-то причине на HTC One и других устройствах мои потоки или службы останавливаются без какого-либо уведомления, предупреждения или ошибки. Приложение продолжает работать, но любой сервис/поток, который запускает все потоки, просто завершается.

Что я пробовал:

  • Использование ExecutorService (пул потоков) для запуска и управления всеми потоками
  • Запускать потоки в AsyncTask с помощью ExecutorService
  • Запускать потоки в связанной службе с помощью ExecutorService
  • Запустить потоки в службе START_STICKY и startForeground

Logcat от HTC One с START_STICKY и startForeground (только что сохранил данные под названием POI, начиная загрузку с номера 26, затем останавливая):

05-23 14:52:54.732: D/libc(17514): [NET] getaddrinfo+,hn 13(0x6170692e706172),sn(),family 0,flags 4
05-23 14:52:54.732: D/libc(17514): [NET] getaddrinfo-,err=8
05-23 14:52:55.363: D/historie(17514): save POI id: jtyvZD9bX9
05-23 14:52:55.383: D/historie(17514): Starting poi number: 26
05-23 14:52:57.595: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative RSSI = -65 abnormalRssiCnt = 0 newLinkSpeed = 72
05-23 14:52:57.595: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative mLinkspeedCount = 1, mLinkspeedSum: 72
05-23 14:52:59.998: D/PMS(705): acquireWL(4237bc08): PARTIAL_WAKE_LOCK  AlarmManager 0x1 705 1000
05-23 14:53:00.028: D/PMS(705): releaseWL(4237bc08): PARTIAL_WAKE_LOCK  AlarmManager 0x1
05-23 14:53:00.048: I/ClockThread(996): now=1400849580059 next=59941
05-23 14:53:00.068: W/MastheadClock(1546): mDigitAnimMin.start
05-23 14:53:00.608: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative RSSI = -65 abnormalRssiCnt = 0 newLinkSpeed = 72
05-23 14:53:00.608: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative mLinkspeedCount = 2, mLinkspeedSum: 144
05-23 14:53:03.642: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative RSSI = -65 abnormalRssiCnt = 0 newLinkSpeed = 72
05-23 14:53:03.642: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative mLinkspeedCount = 3, mLinkspeedSum: 216
05-23 14:53:06.675: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative RSSI = -64 abnormalRssiCnt = 0 newLinkSpeed = 72
05-23 14:53:06.675: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative mLinkspeedCount = 4, mLinkspeedSum: 288
05-23 14:53:09.698: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative RSSI = -64 abnormalRssiCnt = 0 newLinkSpeed = 72
05-23 14:53:09.698: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative mLinkspeedCount = 5, mLinkspeedSum: 360
05-23 14:53:09.698: D/WifiStateMachine(705): fetchRssiAndLinkSpeedNative: Update RSSI:-64 and linkspeed:72 in database
05-23 14:53:09.698: D/WifiApDatabaseHandler(705): updateConnectedAP...

Изменить 1:

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


person Warpzit    schedule 23.05.2014    source источник
comment
300+ тем? Серьезно... зачем тебе это?   -  person Squonk    schedule 23.05.2014
comment
@Squonk Он находится в пуле потоков, поэтому, если быть более точным, 1-2 потока выполняются много раз ...   -  person Warpzit    schedule 23.05.2014
comment
Приложение продолжает работать — как вы это определили? Скорее всего, ваш процесс завершается.   -  person CommonsWare    schedule 23.05.2014
comment
@CommonsWare Да, процесс завершен, но если у меня есть асинхронная задача, которая загружает контент, я все еще могу перемещаться по кнопкам и перемещаться в приложении, просто без данных. Если в сервисе служба не убита, то она просто останавливается и иногда снова возобновляется.   -  person Warpzit    schedule 23.05.2014
comment
попробуйте это, stackoverflow.com/questions/6318943/   -  person mani    schedule 23.05.2014
comment
@ mani345 не совсем полезно. Я хочу, чтобы это продолжалось, а не останавливалось.   -  person Warpzit    schedule 23.05.2014
comment
Если у вас есть только 1-2 потока, которые постоянно выполняются снова и снова, GC, вероятно, не очистит их правильно, поскольку объект очищается только тогда, когда все ссылки на него были освобождены. Возможно, стоит взглянуть на различные типы ссылок.   -  person Joep_H    schedule 26.05.2014
comment
В HTC One есть режим разработчика (активируется несколькими нажатиями на «Настройки» > «О программе» > «Информация о программном обеспечении» > «Дополнительно…», когда вы нажимаете «Номер сборки»), пробовали ли вы играть с различными настройками, такими как ограничение фоновых процессов и т. д. (возможно, это активно на устройстве?)? Если не считать того, что у устройства HTC меньше памяти, чем у вашего Samsung, и система раньше останавливает фоновые процессы...   -  person Leo K    schedule 26.05.2014
comment
@Arcshade, это не должно быть проблемой, поскольку вызов System.gc() вручную решает проблему.   -  person Warpzit    schedule 26.05.2014
comment
@LeoK Я не играл с этим, нет. Но я хочу, чтобы он работал без каких-либо дополнительных настроек.   -  person Warpzit    schedule 26.05.2014
comment
@Warpzit Я думал, может быть, он уже включен на устройстве и ограничивает его. Однако более вероятно, что вы просто используете слишком много памяти/процедур. для фонового приложения, и на устройстве его меньше. Пробовали ли вы использовать приложение для мониторинга ресурсов и сравнить производительность двух устройств с вашим приложением, работающим в фоновом режиме...?   -  person Leo K    schedule 26.05.2014
comment
@LeoK еще нет, но я пришел к тому же выводу = проблема с памятью. Есть несколько других проблем с этим приложением, просто надеюсь, что я смогу сделать его сносным.   -  person Warpzit    schedule 26.05.2014
comment
Рассматривали ли вы возможность использования IntentService? Это только один поток, но он всегда выполняется в фоновом режиме. И получаете ли вы wakelock во время загрузки?   -  person rootkit    schedule 29.05.2014
comment
@rootkit, ты действительно читал то, что я пробовал? Запустить потоки в службе START_STICKY и startForeground   -  person Warpzit    schedule 30.05.2014
comment
Я сделал. Тем не менее, потоки, которые вы запустили из своего закрепленного сервиса переднего плана, все еще могут быть уничтожены Android. Я бы попробовал IntentService вместо того, чтобы запускать новые потоки, поскольку он управляется Android и вряд ли будет убит.   -  person rootkit    schedule 30.05.2014
comment
@rootkit Спасибо за дополнительную информацию, попробую, если (не дай Бог) снова попаду в такую ​​же ситуацию.   -  person Warpzit    schedule 30.05.2014


Ответы (3)


Возможно, вы достигли предела количества потоков, которые может обработать система Android. Вы упомянули, что используете ExecutorService. По умолчанию только 5 потоков могут выполняться одновременно, и ограничение в 128 потоков может быть поставлено в очередь.

См. исходный код AsyncTask CORE_POOL_SIZE — это количество задач, которые могут выполняться одновременно, MAXIMUM_POOL_SIZE — это количество потоков что можно поставить в очередь.

person bvanvelsen    schedule 28.05.2014
comment
Хороший ввод, хотя я уверен, что это была проблема с памятью, поскольку System.gc после выполнения каждого Runnable решил проблему. - person Warpzit; 28.05.2014

Запуск GC никогда не является решением! это просто признак плохой реализации кода.

Вы не предоставили код, но из описанного вами сценария вы переполняете систему объектами и данными, и поэтому вам нужно время от времени вызывать GC.

Убедитесь, что вы повторно используете свой объект, например. - даже если вы используете threadPool - вы повторно используете runnables или просто создаете новый runnable для каждого потока?

Например, если вы используете Task, обязательно отмените и очистите его TimerTask. Очистка очистит все завершенные задачи,

Эту проблему создает не параллелизм потоков, поскольку только 2 потока живут синхронно.

person Nativ    schedule 31.05.2014
comment
Задачей не пользовался. Но не использовал повторно мои runnables, хотя это можно было сделать. Спасибо за ваши указатели. - person Warpzit; 01.06.2014

Решение, которое я использовал, работает без сбоев и зависаний:

System.gc();
startNewThreadAction();

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

person Warpzit    schedule 30.05.2014
comment
Запуск GC таким образом не гарантирует, что он будет работать в тот же самый момент. Это в основном хак для более серьезной проблемы с памятью, которая у вас есть. Я предлагаю провести больше исследований по этому вопросу, пытаясь проанализировать количество потоков, которые вам действительно нужно вызывать, и, возможно, даже изменить способ загрузки всех этих данных. - person Udinic; 31.05.2014
comment
@Udinic Я знаю и согласен. Но проект не в моих руках, поэтому я ничего не могу с ним поделать. Если бы у меня было право голоса, я бы изменил способ загрузки данных. Но теперь не в моих руках. - person Warpzit; 31.05.2014