В среднем, если вы не пишете калькулятор, будильник и прочее, то либо вы очень классный, большой молодец и все сделали хорошо, либо ваше приложение занимает 150–170 мегабайт.
— Меня зовут Артур, я Android-разработчик, работаю над приложением «Яндекс». Сегодня я поделюсь с вами историей о том, как мы адаптировались под Android Go. Расскажу, на какие грабли мы наткнулись, что у нас не получилось и вообще как это все работает, зачем оно надо.
Небольшое отступление о том, что это вообще такое. Android Go — специальная версия Android, которая предназначена для дешевых устройств. Они стоят 60–100 долларов, и поэтому они очень слабенькие, медленные, тормознутые. Так что Google для них решил сделать свою систему, чтобы они хоть как-то нормально работали. Ее анонсировали на Google I/O в 2017 году, то есть прошел уже год и несколько месяцев. Поэтому, когда анонсировали митап, прозвучал логичный вопрос: «Вы еще живы, что ли?». Я тогда сказал, что все хорошо, все нормально, я расскажу. А теперь я как типичный интернет-герой буду отвечать постфактум, почему так произошло.
![](https://habrastorage.org/webt/h2/qw/6g/h2qw6gttth_hx-niydwklvvcb8u.jpeg)
Что именно произошло? Google сказал: «Мы делаем такую систему». Потом он сказал: «Окей, нам нужно время на доработку» и все такое. После этого у вендоров всегда бывает какая-то задержка в адаптации этой версии под себя. А новая версия у нас и так выходит не раньше, чем через год, поэтому здесь ничего удивительного нет. К тому же им требовалось решить, надо ли вообще делать такую штуку: речь идет про дешевые устройства и непонятно, будет от них профит или нет. К тому же этот девайс должен быть новым, его надо сделать, научиться продавать, понять, как он будет работать.
Первый смартфон с Android Go появился не так давно. Где-то в апреле, наверное, начались продажи, а может, в мае. Это Nokia 1, он продается везде. У меня он тут валяется. Сейчас, по-моему, на рынке есть всего штук девять таких смартфонов, но к концу года их обещают больше сотни. И в принципе, еще никто из крупных игроков типа Huawei, Samsung и прочих не сказали свое слово, поэтому они еще что-то добавят, не смогут остаться в стороне от такого большого рынка.
Я перед докладом зашел на страничку Android Go и увидел, что они сделали Android Pie Go Edition. Но они там ничего не сделали, просто заранее уменьшили количество установленных приложений и их вес. Сказали: — «У вас теперь в два раза больше свободного места». И стандартные отмазки: bug fix, улучшение производительности, все дела. Но хоть назвали, а значит, не забыли.
Какие ограничения этих устройств, если говорить конкретно? Во-первых, у них 512 мегабайт или 1 гигабайт оперативной памяти, 8 или 16 гигабайт storage. Понятно, что при таких условиях они крайне тормознутые и все нормальные приложения на них будут работать примерно так же тормознуто. Чтобы на них приложения работали с минимальной адекватностью, Google сказал: «Давайте введем следующие требования». Они вполне логичны, вытекают из того, что было на предыдущем слайде.
![](https://habrastorage.org/webt/ci/xm/ht/cixmhtwrdwbu_gkczbo0vk3-k8e.jpeg)
В первую очередь это абстрактная хорошая производительность. Ваше приложение должно хорошо и быстро запускаться и работать на таком устройстве. Мы такие: «Отлично. Работаем».
Дальше уже конкретные числа, которым надо соответствовать. Занимаемое место после распаковки и установки APK — не больше 40 мегабайт. Иногда это проблема, потому что у кого-то и APK весит все 80 мегабайт. Будет больно. Более того, это нельзя адекватным образом взять и померить. То есть вы не можете сказать: «Я знаю, что у меня APK весит столько-то, поэтому после установки приложение будет занимать столько-то». Все это очень сильно зависит от вендора, версии устройства, Android и т. д. Но если у вас APK занимает 10 мегабайт, то, в принципе, все нормально и вы никогда не превысите это число.
И теперь самое веселое и классное требование: потребляемая оперативная память во время работы с приложением не должна превышать 50 мегабайт.
Кто знает, сколько оперативной памяти его приложение в среднем занимает во время работы? Кто когда-нибудь интересовался этим вопросом? Есть те, у кого меньше 100 мегабайт? Красавчик. Но, возможно, вы врете. В общем, в среднем, если вы не пишете калькулятор, будильник и прочее, то либо вы очень классный, большой молодец и все сделали хорошо, либо ваше приложение занимает 150–170 мегабайт. Засунуть это в 50 мегабайт очень сложно. Поэтому все остальное время мы будем говорить об этом, будем обсуждать, как засунуть глобус в сову, и т. д.
![](https://habrastorage.org/webt/6k/el/g1/6kelg1qxjmzqgltficsia2dk1p0.jpeg)
Что включает наш разговор по памяти? Непосредственно нужно понять, что именно мы меряем, дальше как лучше всего это померить. Также для Android Go устройств есть своя специфика, которую нужно учитывать, и мы о ней тоже поговорим. И я также расскажу какие-то общие вещи, общие советы, о которых вы, возможно, не догадывались, но они реально могут отожрать у вас кучу памяти.
В 2018 году после того, как прошел Google I/O, начинать рассказ про память нужно обязательно с отсылки к этому докладу. Кто его смотрел?
Отлично. Все остальные 180 человек знают, чем заняться в ближайшее время. На мой взгляд, это один из лучших докладов на Google I/O. Чувак рассказал нереально крутые вещи. Он рассказал все по полочкам, хорошо, и со многими глубокими деталями. Те, кто смотрел его и хорошо помнит, наверняка заметят, что я оттуда скопипастил некоторые вещи, потому что иначе нельзя, он рассказал все, поэтому я буду повторять.
Что мы меряем? Там была такая штука, которая называлась PSS (Proportional Set Size). То есть оперативная память в Android представлена некоторыми блоками по 40 килобайт, и эти блоки могут как полностью принадлежать приложению, так и шариться между процессами и приложениями.
И вопрос: как именно понять, к какому приложению относить эту расшаренную память? Есть несколько подходов, они вполне логичные. PSS говорит, что если память шарится между N процессами, значит, мы будем считать, что вашему приложению принадлежит 1/N этой памяти. И абсолютно аналогично есть Residential Set Size и Unique Set Size, который говорит, что «Ничего из shared-памяти не принадлежит мне» и «Все принадлежит». В принципе, PSS здесь самый логичный.
Как именно можно померить потребляемую память? Здесь все просто. Либо это профайлер в Android Studio, либо это dumpsys. Есть, конечно, другие тулзы. Они могут вам дать более детальные результаты, что-то более сложное, но проблема в том, что для понимания их результатов, для их использования все это очень-очень сложно. Часто вам нужен либо root, либо кастомная сборка Android. И они вам по большому счету не нужны, достаточно первых двух инструментов.
![](https://habrastorage.org/webt/0r/--/pr/0r--prgyak0-hltivshg-dxeuqc.jpeg)
Ссылка со слайда
По профайлеру в Android Studio я говорить не буду, думаю, многие им пользовались. Кто еще не пользовался, обязательно потыкайте. В частности, я привел ссылку внизу — просто хорошая статья из документации с видео, как им пользоваться, с демками. И, в принципе, все понятно. Он показывает, куда у вас уходит память, показывает это в режиме реального времени. Единственное, что нужно помнить — что он все-таки накладывает определенные погрешности, которые возникают от того, что мы постоянно меряем эту память. Но они в пределах допустимого.
![](https://habrastorage.org/webt/gb/fv/wn/gbfvwnjxm6fcggr66eoyzmcvnni.jpeg)
Ссылка со слайда
Dumpsys — простая консольная штука, которая не требует от вас ничего, только подключенного телефона и adb. И можно выполнить такую команду: вызвать dumpsys meminfo, передать ему пакет, и он вам вернет примерно такую картинку. И если у нас интересует, сколько именно потребляет наше приложение, то мы можем посмотреть конкретно на TOTAL, которая говорит, что «Ваше приложение жрет около 168 мегабайт». Много, но что поделать?
![](https://habrastorage.org/webt/lm/yo/xw/lmyoxwiahsbeey_ru-3zvdtd8y0.jpeg)
Ссылка со слайда
Также он показывает вам разбивку, что именно в этой потребляемой памяти сколько места занимает. Здесь есть различные участки, они сложные, мы поговорим о них дальше, но пока можем заметить основное — это Java Heap, наши джавовые объекты, а все, что дальше — это сложнее.
Что еще важного? Память — это очень чувствительная вещь ко всяким тестам и всяким внешним условиям. То есть все тесты вы должны выполнять как можно более в одинаковых условиях. Понятно, что это должен быть в идеале один девайс, потому что память зависит от версии Android. Здесь достаточно вспомнить различия между четверками и пятерками. Зависит от размера или разрешения экрана, потому что чем больше размер экрана, тем больше контента влезает, тем больше памяти нужно, чтобы все это отрисовать. Разрешение чем больше, тем больше пикселей занимают ваши bitmap, и тем больше памяти требуется на их хранение.
Сценарий работы с приложением тоже влияет на тесты. Вы можете читать текст или вы можете скроллить галерею с кучей картинок. И понятно, где памяти будет больше.
Еще одна важная вещь — загруженность устройства. То есть у вас может быть все одинаково, но при этом в одном случае у вас ваше приложение единственное работающее, а в другом случае у вас куча приложений, которые еще что-то в фоне делают, что-то качают, удаляют, работают на foreground, и при этом у вашего приложения просто отжимают память, потому что надо отдать другим приложениям. Поэтому в идеале лучше взять и сначала убить все другие приложения, которые работают, не ваши. Все, до чего можете дотянуться, то убейте. Просто в таком случае и PSS в точности скажет вам спасибо, потому что не надо будет шарить память между процессами.
![](https://habrastorage.org/webt/lm/yo/xw/lmyoxwiahsbeey_ru-3zvdtd8y0.jpeg)
Можно, например, взять и посмотреть текущую информацию по свободной памяти, по занятой памяти. Он вам выведет примерно такую табличку, которая говорит, что «Вот у меня свободной памяти столько, кэшированной памяти столько, занятой памяти столько». И если у вас там есть 200–250 мегабайт свободной памяти для себя любимого, то это хорошо, скорее всего, тогда ничто не повлияет на ваши тесты.
Возможно, у кого-то сейчас возник вопрос «Зачем мне все это надо?». Это такой перерывчик, в котором я дополнительно скажу мотивацию для всего этого.
Во-первых, даже если вы сейчас не собираетесь ничего делать под Android Go и думаете, что он сдох, он вполне может развиться, прийти к вам, и вам в какой-то момент придется со всем этим разбираться.
Второе, что я считаю очень важным — вы можете просто сделать регрессионные тесты по памяти. То есть вы можете просто написать скрипт, который будет запускать приложение, делать dumpsys, выполнять такие замеры, и смотреть, как у вас меняются эти показатели между релизами. Такой скрипт можно написать за пару часов, настроить инфраструктуру — подольше, но, мне кажется, это неплохая штука.
Если говорить про специфику Android Go — третий наш пункт в борьбе с памятью, — то там есть несколько приятных новостей. Во-первых, никто на самом деле для вас не требует следовать этим ограничениям. То есть вы можете использовать приложение, как оно у вас есть, поставить его на девайс с Android Go, и все нормально. Проблема в том, что пользователь, весьма вероятно, вас удалит, потому что вы занимаете кучу места. Также ваше приложение может медленно работать и есть кучу памяти, да. Но пока никто это не запрещает, потому что иначе не было бы ни одного приложения, кроме гугловских на Android Go. Но если дальше эта штука будет развиваться, многие будут адаптироваться к таким условиям, то, в конце концов, ваше приложение могут просто понизить в выдаче Android Go, или сказать, как бы пользователь будет устанавливать приложение на свой Android Go смартфон, ему могут показать Alert: «Чувак, приложение плохо работает с Android Go. Может, не будешь его ставить?».
Есть еще один момент — вы можете руками из Google Play исключить Android Go девайсы, то есть сказать, что приложение нельзя ставить на Android Go девайсы. Это появилось не так давно.
И Google еще тоже достаточно умный, и 50 мегабайт, которые звучали в названии доклада — это не фиксированная цифра, она зависит от разрешения устройства, от размера экрана, и, к тому же, от типа приложения. Например, играм выделено больше, по-моему, 115 мегабайт. В принципе, это вполне понятно.
![](https://habrastorage.org/webt/gu/yj/0s/guyj0sbre79wfwrlzgupt009xn0.jpeg)
Ссылка со слайда
Что если говорить непосредственно про этот тест? Есть еще один момент, который в частности очень сильно касается нас — работа с предустановками. Когда вендоры делают новый телефон, они часто ставят туда какой-то набор предустановленных приложений. В частности, мы очень сильно этим занимаются, и проблема в том, что там они прогоняют такие штуки как Compatibility Test Suite. Это гугловые тесты, они их прогоняют. И там, если ваше приложение не соответствует этим 50 мегабайтам, то все плохо, и ваше приложение не может быть предустановлено на такое устройство.
К сожалению, тесты, которые делает Google, не из open source, я не могу их рассказать, они под NDA, но хорошие разработчики из Google написали такую статью про Android Go, и там, в принципе, есть рекомендации, которые достаточно хорошие
То есть все банально. Запускаем приложение. Ждем 5 секунд, пока все загрузится. Делаем dumpsys, записываем значение TOTAL, выполняем кучу раз, получаем результат. Все очень просто и банально.
![](https://habrastorage.org/webt/zq/ma/de/zqmadexusg3whja0-dsz0d4w7gk.jpeg)
Единственное, они не учли такую маленькую особенность в своей статье, или, возможно, не стали о ней говорить — есть такая штука, как работа в другом процессе, и часто ее делают для того, чтобы бороться в том числе с потреблением памяти.
Кто считает, что это хорошо для Android Go? А кто считает, что это плохо? Смело.
![](https://habrastorage.org/webt/_c/4p/h5/_c4ph5f7gcnhakefypwspum8d_y.jpeg)
Проблема в том, что, да, это плохо, потому что в итоге ваша потребляемая память приложения считается по всем процессам. Если мы сделаем такой пустой процесс без ничего и возьмем dumpsys именно этого процесса, то увидим, что он занимает 7 мегабайт. 5-8 мегабайт — это такой оверхед от создания процесса. Поэтому, когда мы боремся за каждый мегабайт, чтобы втиснуть это все в 50, то такая штука дается нам очень плохо. В частности, допустим, у «Яндекс» самая популярная библиотека «Яндекс.Метрика», она тоже работает в другом процессе, и это тоже может давать нам боли.
![](https://habrastorage.org/webt/qu/os/fu/quosfu3kccdztjv7cp6ujn4rxhg.jpeg)
Поэтому, если вам приходят, допустим, какие-то external-библиотеки, вы можете просто сказать: «Чувак, работай, пожалуйста, в главном процессе. Я согласен, что это может быть медленнее, но зато оно не будет жрать лишнюю память». Так что это тоже тонкий момент.
![](https://habrastorage.org/webt/ci/6b/9c/ci6b9cbpebgounzlbc87xids-xi.jpeg)
Если говорить по потреблению памяти, то давайте перейдем к этой табличке, что там есть. Берем пустой проект, и запускаем этот dumpsys, натравливаем на это дело, и видим, что 23 мегабайта из 50 уже занято. Пустой “Hello, world!” без ничего, просто активити с текстом. Становится довольно грустно. Еще более грустно становится от осознания того факта, что непосредственно влиять мы можем на такой параметр как Java Heap, то есть это непосредственно наши джавовые объекты, которые можем отслеживать явно, которые можем удалять, уменьшать и хоть как-то взаимодействовать.
А с этим всем делом нормально взаимодействовать сложно, потому что это всякий фреймворковский код и непосредственно из Java у вас просто нет нормальных тулзов, чтобы понять, как все это используется. Но приятная новость, что мы можем на все это дело влиять опосредовано, поэтому давайте поговорим, что такое там есть.
![](https://habrastorage.org/webt/pa/p_/qp/pap_qprhxuqhr59pnjx8kxrqwos.jpeg)
Что такое Java Heap — понятно. Что такое Native Heap — тоже достаточно логично предположить. Это те же самые аллокации, только плюсовые. Они приходят из фреймворка и из ваших нативных библиотек, файлов .so и прочего.
Код — это непосредственно то, что относится к хранению кода. Это размер вашего .dex, это ваши .so, это ресурсы, mmap-файлы и все это. То есть чем меньше кода, тем лучше. Самая простая истина, которая работает вообще про все.
Stack — это стек Java/C++ потоков. То есть у каждого потока есть свой стек вызовов, поэтому каждому потоку создается такая определенная область памяти для хранения всего этого дела.
Graphics — это отрисовка UI. Там частично хранятся и битмапы, которые отрисовываются, и то, что с этим связано.
Private other, System — это что-то, на что мы совсем влиять не можем, и, по сути, все остальное, что не очень сильно поддается категоризации.
![](https://habrastorage.org/webt/ut/mv/ft/utmvfteatf-vvzdda5_a8f-iyvi.jpeg)
Если говорить про нативные библиотеки, то, допустим, взять можно пустое приложение… можно взять обычное приложение, которое есть у нас, и взять из него dumpsys, увидеть, что он занимает 146 мегабайт. А если пойти и выпилить кое-что… в частности я взял и выпилил две самые большие нативные библиотеки, которые у нас есть в сумме на 15 мегабайт, и взять dumpsys после этого, можно легко увидеть, что у нас пропало потребление из Native Heap и из кода. То есть таким простым жестом мы сэкономили себе порядка 35 мегабайт. Достаточно неплохо.
![](https://habrastorage.org/webt/zn/9r/9v/zn9r9v35dja5ndfyz4nwinzshys.jpeg)
Потоки. Сделаем самый простой тест. Есть пустое приложение, и есть то же самое пустое приложение, где мы возьмем и сделаем цикл, который будет делать new Thread(), в нем sleep на пять секунд, и запускать этот поток. Можно увидеть, что в таком случае у нас сильно пополняется стек. То есть на все это дело мы можем влиять, но опосредовано, уменьшая количество потоков в Java-коде. То есть через Java-объекты в том числе влиять на все эти локации, которые есть в других элементах.
![](https://habrastorage.org/webt/4i/ed/mo/4iedmo77bys7vs6hv-f65oiuta0.jpeg)
Если продолжать говорить про потоки, то можно легко посмотреть, что у вас есть за потоки, что они делают в приложении. Есть разные инструменты. Можно тем же systrace, можно просто консолькой найти id вашего процесса, и грепнуть ps по тому, какие потоки есть вообще в системе.
Если вы хорошо делаете и используете всякие ThreadFactory, чтобы именовать ваши потоки, то вы можете понять, что у вас должно быть, что не должно быть, и таким образом уменьшить все это дело, потому что 100 потоков в приложении иметь особо бессмысленно.
Что еще можно сделать? Есть полностью известный набор баянных советов: следите за утечками, используйте пулы, не создавайте объекты, когда не надо, и вся эта ерунда, все это применимо. Отлично.
Есть хорошая зависимость между тем, сколько ваше приложение потребляет памяти, и тем, насколько оно большое. То есть чем больше ваше приложение, тем больше памяти оно будет жрать, поэтому, по-простому, уменьшайте вес APK, уменьшайте вес .dex, уменьшайте .so, убирайте все, что можно убрать.
Уменьшение памяти невероятно плохо сочетается с оптимизацией. Допустим, мы хотим сделать самый простой кейс, когда пользователь скроллит ленту картинок, картинки подгружаются из сети. Что мы делаем в таком случае, чтобы пользователь видел картинки быстрее? Мы заранее — пока он еще не доскроллил до этих картинок — начинаем подгружать нужные картинки, чтобы он не видел серые квадраты. В таком случае, если мы говорим про память, то мы будем просто занимать память этими картинками. Поэтому память и оптимизация крайне плохо сочетаются. В смысле — оптимизации такого типа.
![](https://habrastorage.org/webt/3s/mv/wk/3smvwkzryvrsm1klctrsmnxtx4i.jpeg)
Если посмотреть на dumpsys, то он хороший, он выводит вам много чего интересного, кроме непосредственно потребления памяти. Например, количество ваших объектов, типа количество View, количество WebView, количество Assets, информацию по базам данных.
![](https://habrastorage.org/webt/yd/m_/92/ydm_92wzagxi-1a9zpwzkeqbe8o.jpeg)
В принципе, базы данных занимают не так много, но, возможно, если вам критичен каждый килобайт, то придется использовать SharedPreference вместо SQLite в каких-то случаях, и, возможно, это вам поможет.
![](https://habrastorage.org/webt/1f/fs/ct/1ffsctcvhhohxpwiysekmopqwzk.jpeg)
Также, например, очень приятно посмотреть на выделенные Assets. В частности, самое популярное, что можно увидеть –это шрифты. И эти шрифты занимают 1,5 мегабайта. Опять-таки, когда мы боремся за каждый мегабайт, то нежные дизайнерские чувства посылаются далеко в первую очередь. Да простят меня коллеги.
![](https://habrastorage.org/webt/q5/7g/ki/q57gkiv47412jj1q9_aye3k_4e8.jpeg)
Неожиданно отвратительная вещь — это WebView. Если создать пустую активити, запустить WebView, загрузить страницу Яндекса, взять dumpsys, будет 100 мегабайт, просто сразу. Если открыть, допустим, какие-нибудь картинки, проскроллить пару раз, то 300 мегабайт — легко. Даже несмотря на то, что WebView хромовское, а процесс считается ваш. Так-то.
![](https://habrastorage.org/webt/o9/pj/z8/o9pjz8exyayhtg1varn-wtsmw8i.jpeg)
Google об этом знает. Они сделали небольшой хак. То есть у них есть WebView, у них есть приложение Google, в котором можно что-то искать. Поисковая выдача открывается в WebView. Нормально.
![](https://habrastorage.org/webt/nt/lp/-q/ntlp-qwbjnysaljhmmahewkcdeq.jpeg)
И есть приложение Google Go, которое предназначено для Android Go-устройств. И здесь они открывают выдачу уже нативно, то есть они создают какой-то layout для отображения этой выдачи, они отображают все это нативными компонентами. А все, что нужно открыть непосредственно в браузере, открывают не в своем внутреннем браузере, а в Chrome Tabs, чтобы Chrome разбирался с этим делом. Такие вот хитрости.
Если говорить про приложение непосредственно под Android Go, то что тут интересного? Тут есть определенные специфики, как именно разрабатывать приложение под Android Go, и давайте немножко поговорим об этом.
![](https://habrastorage.org/webt/rm/jz/cf/rmjzcfwjkfponuuzuljvu0r088q.jpeg)
Есть несколько способов. Во-первых, у вас все может быть классно, приложение может работать хорошо, и вы можете его отдавать для Android Go без всяких доработок. То же самое в случае, если вы пишете будильник, калькулятор. Но чаще всего у вас с этим все сложно, поэтому вам нужно, допустим, сделать какие-то build флаги, отключить какие-то модули, фичи на этапе компиляции, еще что-то сделать. И таким образом у вас будет две APK, и вы можете загрузить одну как обычную, вторую — использовать uses-feature «low-memory», и это будет как две APK.
Либо же вы можете сделать два приложения, то есть одно приложение обычное, другое приложение специально заточено под Android Go. Так делает Google. Они, в частности, выпустили Go-версии многих своих приложений.
Что здесь хорошего, что здесь плохого? Хорошо то, что вы изначально делаете новое приложение, и если вы изначально будете что-то в нем писать и превышать потребление памяти, то вы скажите: «Ага, делал что-то не то. Пошел делать нормально». И вам не нужно сразу уменьшать эту память в четыре раза. К тому же, это хорошо и это легко, а плохо в том, что вам нужно сделать новое приложение, к тому же, оно должно быть как-то поддерживаемо, одинаково с фичами с основным приложением, и как-то вместе оно должно сочетаться. Это требует огромную кучу ресурсов, и, в принципе, делать это не надо, если вы не Google, потому что если Google не будет делать такие приложения, то никто их не будет делать. А сейчас вам делать такое приложение не надо, потому что это требует кучу ресурсов, и непонятно, действительно ли Android Go хорошо выстрелит, и будет действительно очень много таких устройств, или же это будет довольно нишевая доля.
В любом случае, вам здесь очень хорошо поможет многомодульный подход, потому что вы можете легко отключить модули, еще что-то. Это очень хорошо.
![](https://habrastorage.org/webt/6r/wd/i-/6rwdi-8mzeuwfvvw00dh0nmdf48.jpeg)
Ссылка со слайда
Еще один довольно важный момент из доклада, который был на Google I/O: ребята правильно говорят, что не надо бояться для таких слабых устройств отключать какие-то свои фичи в рантайме. Возможно, у вас есть очень клевый фоторедактор, который может делать все, что угодно, накладывать любые фильтры, но он требует кучу-кучу памяти, и на слабом устройстве он будет работать плохо. Поэтому не бойтесь сказать, что «Давайте не будем на вашем устройстве запускать фоторедактор, потому что у вас слабое устройство. Купите нормальное». Так что это график хороший. Это график зависимости количества фич от потребляемой памяти, и наоборот. И этому можно следовать, в принципе.
Что еще стоит учесть? Понятно, что здесь вопрос не только памяти. Память — самое сложное, самое интересное и то, с чем мы возились 98% времени. Но понятно, что надо думать в том числе о скорости работы, запуске, потреблении батарейки и т. д. К тому же вы можете сделать какие-то дополнительные фичи для Android Go-приложений. В частности, в YouTube Go есть возможность скачать приложение для просмотра офлайн. В основном приложении YouTube такого не было, и, может быть, нет и сейчас. Не знаю. Дело в том, что девайсы с Android Go будут использоваться в странах, где, возможно, не очень хороший интернет — поэтому давайте скачивать заранее. Есть другие хорошие примеры — Facebook Lite, Twitter Lite, а также Яндекс.Браузер Lite, потому что не всем нужны какие-то полностью функциональные фичи. Кому-то, может быть, нужна только переписка или только посты. Незачем скачивать огромный Facebook, когда можно поставить маленький. И все это должно быть для пользователей, вы должны подумать и сделать так, чтобы им было хорошо. Вообще, это классный челлендж — сделать такое приложение, чтобы оно работало под Android Go.
Что еще по ссылочкам? Есть классный ответ на Stack Overflow, который набрал почти 1000 лайков. Вы можете помочь ему набрать еще. Ответ разъясняет, что вообще с памятью, что за что отвечает, что чем является в памяти. И, в принципе, весь этот ответ — по dumpsys.
Знают ли это многие или нет, но Android может работать с устройствами, у которых 512 мегабайт оперативной памяти, только начиная с Android 4.4. Там как раз таки появился специальный API для взаимодействия с такими устройствами, и это вам может помочь.
Здесь можно было бы закончить, это было бы красиво. А теперь о том, как это было у нас на самом деле. Если коротко — не так красиво, совсем не так красиво.
Пришли ко мне в мае, сказали: «Надо сделать». Я сказал: «Хорошо». Пошли разбираться. Почитали — все хорошо, кроме памяти. Память где-то 170 мегабайт. Отличный старт. Надо каким-то образом уменьшить. Что проще всего сделать? Взять и отключить все отключаемые модули, посмотреть, что происходит, потому что надо сделать так, чтобы оно хоть как-то работало. Если там не будет каких-то фич — ну и ладно. Осталось 105 мегабайт. Было больно.
![](https://habrastorage.org/webt/mv/qk/gj/mvqkgjfuippyzhhhcv0tmkosqzw.jpeg)
Поэтому дальше пошел большой рефакторинг. На основе build-флага началась переделка всего-всего. Сделали densitySplit, чтобы ресурсные таблицы занимали меньше, resConfig, оставили там только русскую и английскую локали. Кэш картинок подкручен, предзагрузка убрана, все оптимизации убраны — боль. ProGuard подкручен еще сильнее. В частности, у ProGuard есть инлайнинг, который позволяет уменьшить количество методов, а взамен, возможно, пожертвовать производительностью, в том числе и читаемостью у stacktraces.
Дальше пошел уже совсем большой рефакторинг. Перенос еще больше в модули, чтобы все это можно было отключать, чтобы было красиво и чтобы Android Go-приложение можно было собирать из нашего основного приложения.
После недельки осталось где-то 64 мегабайта. Я думаю: «Хорошо, надо сегодня закончить». Прошло 14 часов, время 4 утра, памяти 60 мегабайт. И я уже не знаю, что делать дальше. Все бесит. Более того, это стало уже необратимым рефакторингом. Поэтому на следующее утро было принято волевое решение — все это не то, жизнь отвратительна, ненавижу все, и делаем специальную новую ветку, начинаем все с нуля. Берем и удаляем весь код, которого, скорее всего, не должно быть в Android Go, и чиним ошибки компиляции. 10 часов, APK с оставшейся основной функциональностью готова, тесты проходят, прекрасно. Проблема в том, что эта штука неподдерживаемая, она у нас есть и все.
Таким образом, самое хорошее решение — это второе приложение. Однако тратить на него ресурсы мало кто даст, пока непонятен реальный профит. Возможно, ваша история будет не такая печальная, потому что мне осталось чуть-чуть усилий, я бы еще влез, но мне уже было невмоготу. Но такая вот история. На этой относительно позитивной ноте, наверное, можно и закончить. Всем спасибо.
Комментарии (30)
YMA
17.09.2018 11:29Ещё выглядит как нарастание фрагментации Android, помимо 4 (?) «живых» версий самой ОС еще и версию для Go надо иметь в виду.
Arturka
17.09.2018 14:48Да, гугл не дает расслабиться :)
Но в первую очередь хочется, чтобы это был напоминание разработчикам, что с ростом технологий не все девайсы превращаются во второй пиксель, и всегда надо думать о производительности на слабых устройствах.
Но вообще да, это безусловно новая фрагментация, которая заставляет думать о том, что с ней делать. К счастью, время на эти раздумья еще много.
TimsTims
17.09.2018 12:45После недельки осталось где-то 64 мегабайта. Я думаю: «Хорошо, надо сегодня закончить». Прошло 14 часов, время 4 утра, памяти 60 мегабайт. И я уже не знаю, что делать дальше.
Если даже спецы Яндекса не смогли, то чего уж говорить о других разрабочтиках? Выходит, требования Google в 50мбайт нереальные?Arturka
17.09.2018 14:31+2Реальные. Если делать новое приложение, как и делает гугл.
Засунуть огромное приложение, которое вообще не задумывалось под такую специфику, — это да, весело :)
Но как я сказал, это веселье все равно дешевле, чем поддержка второго приложения. А пока Android Go не распространится широко, поддержка второго приложения может не оправдаться, так что ждем.
Solexid
17.09.2018 12:49Я не увидел проблемы в таком ограничении. Возможно потому что я не использую 40 мб рекламно-трекинговых библиотек, как делает яндекс.
achekalin
17.09.2018 12:55Нельзя так говорить. Вы вот не используете, а для кого-то — это святое! *смайлик*
vics001
17.09.2018 13:40Все сильно-сильно зависит, у нас только иконок для карты на 16 МБ. Вообще любой проект >100K LOC, наверняка будет иметь проблемы.
Solexid
17.09.2018 13:43+1У вас там иконки в разрешении 512х512? Для android go в этом нет никакого смысла, так что я не думаю что это вызовет какие то проблемы.
vics001
17.09.2018 15:04Нет, просто более 4000 маленьких иконок, xhdpi. Понятно, что можно оставить только код, которого 15-20 МБ, а остальное грузить после установки, но удобно ли это?
iLLuzor
17.09.2018 23:24Иконки можно в вектор перевести. Или это векторных иконок 16МБ?
vics001
18.09.2018 14:34Можно, но рендерить вектор еще накладней на таких устройствах. Тут важно «контекст», в Android GO почему-то решили, что 50 МБ хватит всем. Но если у приложения или игры ресурсов на 500 МБ, то хочешь не хочешь их надо загрузить.
В нашем случае, 50 МБ приложения не большая беда по сравнению с 200 МБ карт, без которых приложение почти бесполезно, а тратить время на то, чтобы оптимизировать то, что и так работает — это странно.
Arturka
17.09.2018 14:40-1Я не увидел проблемы в таком ограничении.
Hello World занимает 50% уже сразу. Добавьте пару картинок и развлечение обеспечено :)
В нашем случае это картинки, это Алиса (+ нативная библиотека спичкита), тонна поискового функционала и еще куча различных сервисов. Суммарное количество только нашего Java-кода (без библиотек) — это порядка 500k строк (и да, не рекламно-трекингового). И вот с такими показателями ограничения уже непростые.
Возможно потому что я не использую 40 мб рекламно-трекинговых библиотек, как делает яндекс.
Рекламно-трекинговые библиотеки занимают совсем мало, поверьте. Да и в принципе никаких таких особых библиотек нет. AppMetrica да Ads SDK.Solexid
17.09.2018 14:44+1Приложение виджет мастер серверов для HL, весит 180 кб. Распаковавшись занимает 1-3 мб. Видимо вы забыли убрать такие «архиважные» для разработки под одну платформу вещи, как android.support* библиотеки. Но они не нужны, если вам не нужно поддерживать древние версии андроида ( а в случае с го — одну версию).
Solexid
17.09.2018 14:51+1И да — на самом деле эти саппорт либы вообще не нужны — они были созданы для тех кто не может написать пару строк кода с проверками, если вы уже можете то что описали в статье — то для вас они лишний мусор. Но я бы всё же лучше разделил приложение на 2 версии, так как гугл ясно дал понять это.
Javian
17.09.2018 14:16+1пока непонятен реальный профит.
«Не экономьте на рекламе, охране и страховании». Это приложение — ваша реклама и будущая лояльность пользователя. Когда он обзаведется другим телефоном, то установит уже привычные ему приложения.Arturka
17.09.2018 14:43Очень правильные слова. Поэтому мы и тратим определенные силы на то, чтобы пользователь видел наше приложение и на Android Go. Но для полноценного хорошего экспериенса нужно все же отдельное приложение.
Отдельное приложение требует много времени на разработку, тестирование и поддержку. Пока нет гарантии, что Android Go займет хотя бы 5% рынка, бизнес не пойдет на это. Ведь эти же ресурсы можно пустить на проекты, которые могут с большей вероятностью принести лояльных пользователей :)Javian
17.09.2018 15:13Уверен, что займет, но это не будут пользователи, которые будут что-то покупать. Телефон для детей, для бабушки, для Индии и т.д. Единственное, чем они полезны — они активно общаются и рекомендуют.
Alex_ME
17.09.2018 14:50+1У меня довольно старенький смартфон, LG L90 с 1 Гб ОЗУ и 8 Гб ПЗУ, и когда я вижу приложение, которое весит больше 50 Мб, мне хочется
убиватьнамекнуть разработчикам, что они не правы. Например, ВТБ — 104 Мб. Для сравнения, Blender 2.5 — 44 Мб (актуальная версия — около 300). Да, я понимаю, что одно на Java, другое на C++, но количество функций не идет ни в какое сравнение.Solexid
17.09.2018 14:54А тут уже другая проблема — это рак под именем — хочу писать везде на своём JS. Да и рыночек порешал, что нанять макак закончивших месяц назад курсы гикбрейнса дешевле, чем нанять нативных разработчиков под конкретную ось. Или хотя бы Xamarin.Forms, который явно быстрее и компактнее ( если конечно его не кодила такая же макака).
dartraiden
17.09.2018 15:03В случае с банковскими приложениями причиной может быть встроенный антивирус. Например, в приложении Сбербанка сидит антивирус Касперского и всё это добро не просто весит сотни мегабайт, но и постоянно работает в виде сервиса, будит телефон.
dimka11
17.09.2018 20:35Размер это ладно, а вот сколько они RAM жрут. Вспоминаю J2ME — там 500 КБ на полноценную игру хватало. А в Android обычный виджет потребляет больше 100 мб.
dimka11
17.09.2018 20:38Я понимаю, что графика высокого разрешения.
64 бит
Отдельная Java машина на процесс.
Но всё-таки почему разница в сотни раз.
P.S. кнопки редактирования нет в мобильной версии.
lassana
Выглядит как серьёзный удар по ненативщине.
Arturka
Android Go явно не займет большой % рынка в ближайшем будущем и слишком большой когда-либо. Так что переживут :)
Или выпустят какой-нибудь Flutter Go, хотя это будет сильно непросто, если он не будет встроен прямо в фреймворк.
CheY
Откуда такая уверенность, если не секрет? Если действительно получится телефон «за 50 баксов», то во многих странах с не богатым, но многочисленным населением вполне может распространиться. прежде всего в Индии, конечно.
SUA
Вполне может
У меня например 1Гб оперативы на звонилке (тот самый случай «за <100 баксов», а то падают часто), и еще она умеет игры
А если будет специально подкрученная версия на производительность без лишних свистелок для большинства приложений — они и половину рынка занять смогут (далеко не все могут и хотят потратить 1000+$ на флагман)
jacob1237
Скорее как страх Google проиграть часть рынка Samsung'у с их Tizen'ом.
Вообще никогда не понимал зачем на носимых устройствах нужна JVM, пусть даже и оптимизированная в каких-то моментах.
Те же Apple девайсы никогда не поставлялись с таким огромным количеством памяти на борту. Хотя бы просто из-за отсутствия виртуальной машины и специфической сборки мусора.
Надеюсь что Tizen все-таки даст Гуглу пинка под зад, хотя бы в этой рыночной категории. Давно пора бы.
Whuthering
Начиная с 5ой версии Андроида виртуальная машина не используется, приложения при установке компилируются из JVM байт-кода в нативный бинарь.