21 September 2017

Почему с течением времени Android смартфоны начинают плохо работать. И как это победить (pt.1)

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


Одним из главным предметов, который мы будем обсуждать в этом тексте, является оперативная память (она же ОЗУ, она же RAM). Ниже я постараюсь кратко объяснить, что это такое и с чем ее едят. Если ты, читающий эти строки, понимаешь о чем идет речь, можешь эту часть смело пропускать.


Что такое оперативная память 

Сегодня среднестатистический пользователь смартфонов обычно знает и понимает лишь один тип памяти. Люди ее между собой так и называют -- просто "память", безо всяких уточнений. Речь в данном случае идет о той памяти, которая хранилище. Которая storage. Та самая, которая указывается в конфигурациях типа "iPhone 7 64 Gb" и за которую, как за отдельную опцию, надо деньги доплачивать. Ну чтобы места больше было. Потому что когда оно заканчивается, ты не можешь, например, скачать игру из магазина или даже что-то сфотографировать. И приходиться чистить место, удаляя что-нибудь ненужное...


Так вот, оперативная память она другая и служит для совершенно иных целей. Всю полезную работу в смартфоне выполняет процессор, путем исполнения кода того или иного приложения (ну или кода операционной системы). И вот этот самый процессор может исполнять код приложения только при условии, что этот самый код загружен (из памяти-хранилища) в оперативную память.
Оперативной памяти всегда сильно меньше, чем памяти хранилища. Минимум на порядок, но обычно и еще меньше. Оперативная память сильно быстрее памяти-хранилища. Тут тоже счет идет, как минимум, на один порядок.
Иногда оперативная память это такая же опция, как память-хранилище. Например, смартфон может идти в конфигурациях 4/64 и 6/128 -- тут через дробь указан объем оперативной и постоянной памяти в гигабайтах.
Оперативная память -- одна из ключевых характеристик в конфигурации персонального компьютера или ноутбука. Те, кто разбирается в таких конфигурациях, обычно очень хорошо понимают, что такое RAM.

Оперативной памяти много практически никогда не бывает.
Все смартфоны сегодня многозадачные, а это значит, что если у тебя много оперативной памяти, то смартфон может держать в ней много уже запущенных приложений и пользователь имеет возможность мгновенно между ними переключаться. Если при запуске очередного приложения память кончилась, операционная система прибивает одно из старых, уже запущенных, приложений. А когда пользователь попытается переключиться на него обратно, то приложение начнет загружаться по новой из памяти-хранилища. Как мы помним, память-хранилище она не быстрая, поэтому иногда этот процесс может конкретно затянуться (все зависит от объема и характера самого приложения). Всевозможные скучные надписи "loading..." в начале работы приложения как раз обычно и означают перекачку данных приложения из памяти-хранилища в оперативную память. Частенько из-за такого перезапуска приложения, нужные ему данные выкачиваются по Сети. Классический пример -- браузер, который начинает загружать данные для каждой открытой вкладки. Данные по Сети грузятся обычно еще медленнее, чем из локальной памяти-хранилища.

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

В персональных компьютерах не принято, чтобы операционная система сама закрывала запущенные пользователем приложения. Поэтому когда оперативная память заканчивается, начинается свопинг. Это когда данные из оперативной памяти временно переносятся в память-хранилище (на жесткий или SSD диск). А потом, при необходимости, загружаются обратно. Как мы помним, оперативная память сильно быстрее, чем дисковая, поэтому свопинг обычно вызывает катастрофическое падение производительности.


Android: оперативная память и фоновые задачи 

Теперь, вооружившись знаниями о том, каким бесценным ресурсом является оперативная память, рассмотрим как в Android реализована работа с ней. 

Все находящиеся в оперативной памяти приложения можно условно разделить на две большие группы: собственно приложения и сервисы
Согласно этой классификации "просто приложение" это нечто, имеющее интерфейс для взаимодействия с пользователем. Только одно приложение, находящееся в данный момент на экране, является активным, т.е. может выполняться. Все остальные приложения, находящиеся в памяти, ничего делать не могут и находятся в т.н. кэшированном состоянии, т.е. в состоянии, когда они моментально могут стать активными, при переключении на них пользователя. 
Другое дело сервисы. Сервис это нечто, что, во-первых, не имеет никаких элементов интерфейса (для взаимодействия с пользователем). А во-вторых, может все время выполнять какой-то код, т.е. работать в фоне одновременно с активным приложением и другими сервисами. 

И вот тут начинается самое интересное. Android, в отличии от iOS, штука для разработчиков очень демократичная, в ходу тут философия -- это ж твое приложение, что хочешь, то в нем и делай! Абсолютно любое приложение для Android может породить сервис, т.е. создать нечто, что будет висеть в памяти (занимая бесценное место в RAM!) и еще и что-то делать в фоне при этом (читай -- кушать батарейку!).
В случае жесткой нехватки памяти, операционная система может, конечно, убить сервис, но при этом, во-первых, она предпочитает сначала поприбивать закэшированные приложения (т.е. то, что недавно запускал сам пользователь), а, во-вторых, сервисы имеет ряд механизмов, с помощью которых они заявляет о себе как о чем-то супер-пупер важном, что фактически означает, что ОС постарается запустить их снова при первой же возможности. Такие себе птички Фениксы. 

Практически в любом Android смартфоне с легкостью обнаруживается как минимум полдюжины висящих в памяти сервисов, которые были порождены установленными пользователем приложениями.
Во-первых, сервис нужен практически любой IM программе, а их сейчас столько, что устанешь загибать пальцы -- Viber, WhatsApp, Telegram, Skype, Facebook Messager, Slack... Список можно продолжать до бесконечности.

А когда-то все было очень просто. One app to rule them all...

Следующая категория приложений, которые очень любят держать в памяти мусор, это всевозможные карты и службы такси. По картам, например, сюда попадают и 2gis, и Maps Me. Бонус: коряво написанные программы такого рода не только отжирают бесценную оперативную память, но еще и частенько конкретно бьют по батарейке, т.к. вися в фоне продолжают использовать GPS.
Да и вообще, чуть ли не каждое второе приложение для Android находит повод, чтобы породить сервис и иметь возможность что-то исполнять в фоне. Очень часто это может быть даже какая-то ничтожная игра, которую вы зачем-то установили полгода назад, раз запустили и напрочь после этого забыли. А сервис от нее в памяти висит... Это может быть практически любое приложение. За примерами даже ходить далеко не надо. Отличная смотрелка картинок, которую я обычно использую вместо стандартной "Галереи" -- QuickPic. Да, в ней есть возможность фоновой синхронизации с облачными сервисами, но я эту опцию не использую. А сервис, блин, зачем-то висит. Или, например, прогноз погоды Gismeteo. Я не использую виджет, соответственно, погода может обновляться в тот момент, когда я переключаюсь в приложение. Но нет -- зачем-то висит сервис. И так далее.

В итоге, эта ситуация с сервисами приводит к тому, что вся потенциально доступная оперативная память в Android, условно говоря, делится на две части: одна часть занята сервисами, а вторая -- приложениями, которые запускает пользователь. Приложения пользователя редко когда смогут использовать ресурсы из первой, "сервисной", части, т.е. фактически эта память потеряна навсегда.

В Android есть возможность детально посмотреть, что происходит с обоими этими частями, "памятью сервисов" и "памятью приложений".
Для этого нужно активировать режим разработчика -- в настройках, в разделе информации об устройстве, надо несколько раз тапнуть на поле "Build number" ("Номер сборки"). После этого у вас в настройках появится раздел "Developer options" ("Для разработчиков"), а в нем есть пункт "Running services".

В моем смартфоне картина выглядит так:


Сервисы (плюс текущее активное приложение) в этом инструменте называются "Apps" и занимают в моем случае 1.2 Gb. Ниже карты памяти мы видим их список, в котором отображается время работы каждого из них, а также занимаемую ими память.
При нажатии на "Show cached processes" мы увидим все закэшированные приложения, фактически сегмент, который на приведенном скриншоте обозначен как "Free", и который имеет такой же размер, как и размер сегмента сервисов, т.е. 1.2 Gb. Именно это значение и определяет всю полезную память, которая может быть использована под запущенные пользователем приложения, типа браузера или игр. Не густо, с учетом того, что это расклад на устройстве с 4 Gb RAM и я серьезно поработал над зачисткой ненужного мусора в памяти.

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

Сверх этого, ситуация еще и усугубляется механизмом ОС под названием BroadcastReceiver, которым разработчики приложений злоупотребляют не меньше, чем сервисами. Эта штука дает возможность приложению мониторить заданные события в системе. Событий этих легион -- отправленная или полученная sms, новая фотография, поменялся статус сетевого подключения, телефон был разблокирован и т.д. и т.п. Если подписавшееся на событие приложение в момент самого события отсутствует в памяти, то операционная система его, конечно же, запускает...
Во что это выливается на практике? Разблокируете вы, к примеру, телефон, а он при этом пытается разослать нотификацию куче приложений, которые на нее подписались. Приложений этих в памяти, естественно, нет, потому что там находятся полезные приложения, с которыми пользователь работал перед блокировкой. А раз их нет, а уведомить их надо, то ОС начинает их все запускать. А это, во-первых, нагрузка на CPU, а значит подтормаживания. А, во-вторых, память то не резиновая, новые приложения запускаются, значит уже закэшированные начинают выгружаться. Нажимает пользователь на иконку браузера, чтобы дочитать страницу, которую он читал до блокировки, а браузер заново стартует и страницу эту снова по сети грузить начинает.
Надо сказать, что Google наконец-то осознала насколько опасный механизм она дала в руки разработчикам и лавочку эту таки прикрыла. Теперь подписываться можно только на те события, которые непосредственно касаются самого приложения. Только вот добавили это ограничение в Android 8...


Выводы из всего вышесказанного выходят следующие. Основная причина деградации производительности смартфонов на Android с течением времени -- устанавливаемые пользователем приложения, которые неудачно используют некоторые возможности этой ОС. Каждое такое приложения -- соломинка, которая, в конце-концов, сломает хребет верблюду, исчерпав запасы прочности даже самого крутого флагмана с быстрым процессором и большим количеством RAM.
Очевидный способ борьбы с этой проблемой -- деинсталлировать приложения. Только вот если это хоть как-то подходит для каких-то ненужных и редко используемых вещей, то что делать с теми приложениями, которые хотелось бы продолжать использовать, не просаживая при этом производительность смартфона?

Об этом мы поговорим в следующей части.


No comments:

Post a Comment