开发一个已经熟悉的平台的新方向-总是很有趣。 一方面,您正在扩展客户群,另一方面,您不是在投资从头开始创建软件,而是在使用现有开发。 但是,如果这个方向真的很新,并有自己的特点,那么就不可能用很少的血量来进行管理。 在我们办公室Mosdroid社区的下一次会议上,开发人员Arthur
Vasilov Arturka谈到了Yandex应用程序适应Android Go系统的问题。
平均而言,如果您不写计算器,闹钟等,那么您要么很酷,做得很好并且做得很好,要么您的应用程序占用了150-170兆字节。
-我叫Arthur,我是一名Android开发人员,正在研究Yandex应用程序。 今天,我将与您分享一个有关我们如何适应Android Go的故事。 我将告诉您我们偶然发现了哪种耙子,什么对我们没有帮助,以及它们如何起作用,为什么需要它。
关于全部内容的一小部分题外话。 Android Go是专为低成本设备设计的Android的特殊版本。 它们的价格为60-100美元,因此它们非常虚弱,缓慢,放慢速度。 因此,谷歌决定让他们创建自己的系统,以便它们至少能够以某种方式正常工作。 它于2017年在Google I / O上宣布,也就是一年零几个月了。 因此,在宣布mitap时,提出了一个合理的问题:“您还活着还是什么?” 我会说,一切都很好,一切都很好。 现在,作为一名典型的互联网英雄,我将事后回应其发生的原因。

到底发生了什么事? 谷歌表示:“我们正在制造这样的系统。” 然后他说:“好吧,我们需要时间完成”和所有这些。 此后,供应商在为自己改编此版本时总是会有某种延迟。 而且与我们一起发布的新版本不迟于一年后发布,因此这里不足为奇。 另外,他们需要决定是否做这样的事情:他们在谈论廉价的设备,尚不清楚它们是否会从中获利。 此外,此设备必须是新设备,必须完成,学习如何销售,了解其工作原理。
不久前,首款搭载Android Go的智能手机问世。 4月的某个地方,销售可能开始了,或者5月。 这就是诺基亚1,它随处可见。 我躺在这里。 在我看来,现在市场上只有九种这样的智能手机,但是到今年年底,它们的承诺数量将超过一百种。 原则上,华为,三星等其他主要公司都没有说出自己的诺言,因此他们将增加一些其他东西,他们将无法远离如此庞大的市场。
在撰写报告之前,我转到Android Go页面,看到他们制作了Android Pie Go Edition。 但是他们在那里什么也没做,只是简单地减少了预先安装的应用程序的数量和重量。 他们说:-现在您的可用空间是原来的两倍。 和标准的借口:错误修复,性能改进,所有方面。 但是至少他们打了电话,这意味着他们没有忘记。
这些设备的局限性是什么? 首先,它们具有512 MB或1 GB的RAM,8或16 GB的存储。 显然,在这样的条件下,它们受到极高的抑制,并且在它们上进行的所有正常应用将以几乎相同的方式工作。 为了使应用程序在最小限度内正常运行,Google表示:“让我们介绍以下要求。” 它们非常合乎逻辑,遵循上一张幻灯片的内容。

首先,它是抽象的良好性能。 您的应用程序应在这样的设备上良好且快速地运行。 我们是:“太好了。 我们正在工作。”
此外,已经有我们必须对应的特定数字。 拆包并安装APK后所占用的空间不超过40 MB。 有时这是一个问题,因为某人和APK重达80兆字节。 会疼的 而且,这不能被适当地采取和测量。 也就是说,您不能说:“我知道我的APK太重了,因此安装后,该应用程序将花费很多。” 所有这些都取决于供应商,设备的版本,Android等。但是,如果您的APK占用10兆字节,那么原则上来说一切都很好,并且您永远都不会超过这个数目。
现在是最有趣,最酷的要求:与应用程序一起使用时消耗的RAM不应超过50 MB。
谁知道他的应用程序在运行期间平均需要多少RAM? 谁曾对这个问题感到好奇? 有人小于100兆字节吗? 好帅 但是也许你在说谎。 通常,平均而言,如果您不写计算器,闹钟等,那么您要么很酷,做得很好并且做得很好,要么您的应用程序占用150-170兆字节。 将其放入50兆字节非常困难。 因此,剩下的时间我们将讨论它,我们将讨论如何将地球仪放入猫头鹰中,等等。

我们的记忆对话包括什么? 直接有必要了解我们到底要测量什么,然后才是测量它的最佳方法。 此外,对于Android Go设备,还需要考虑其特殊性,我们还将对此进行讨论。 我还将告诉您一些您可能没有想到的一般性知识和一般性提示,但是它们确实会占用您很多内存。
在2018年Google I / O通过之后,您需要参考
此报告来开始有关内存的故事。 谁看的?
太好了 其余的180个人都知道在不久的将来该怎么做。 我认为,这是Google I / O上最好的报告之一。 杜德说了不可思议的事。 他讲了架子上的所有东西,而且有很多深层的细节。 那些看过并记住它的人可能会注意到我从那里复制了一些东西,因为否则不可能,他告诉了一切,所以我将重复它。
我们要衡量什么? 有一种叫做PSS(比例设置大小)的东西。 也就是说,Android中的RAM由大约40 KB的块表示,这些块可以完全属于应用程序,也可以在进程和应用程序之间翻阅。
问题是:如何准确地了解将哪个共享内存与哪个应用程序相关联? 有几种方法,它们很合乎逻辑。 PSS说,如果内存在N个进程之间混乱,那么我们将假定您的应用程序拥有该内存的1 /N。 并以完全相同的方式存在“住宅集大小”和“唯一集大小”,它表示“共享内存中没有一个属于我”和“所有内容都属于我”。 原则上,PSS在这里是最合乎逻辑的。
您如何精确测量消耗的内存? 这里的一切都很简单。 它是Android Studio中的探查器,还是dumpsys。 当然,还有其他工具。 它们可以为您提供更详细的结果,更复杂的内容,但是问题在于要理解它们的结果,使用它们非常困难。 通常,您需要root或自定义的Android版本。 总的来说,您不需要它们,前两个工具就足够了。

我不会谈论Android Studio中的事件探查器,我想很多人都在使用它。 谁还没有使用过,一定要戳一下。 特别是,我提供了以下链接-只是带有视频的文档中的一篇好文章,以及如何使用它和演示。 并且,原则上,一切都清楚。 它显示了内存的存储位置,并实时显示。 唯一要记住的是,它仍然存在某些错误,这些错误是由于我们不断测量此内存而产生的。 但是它们在可接受的范围内。

Dumpsys是一个简单的控制台程序,不需要您做任何事情,只需连接的电话和adb。 您可以执行以下命令:调用dumpsys meminfo,将软件包传递给它,它将返回类似的内容。 而且,如果我们对应用程序的消耗量感兴趣,那么我们可以专门查看TOTAL,它表示“您的应用程序占用了大约168兆字节”。 很多,但是该怎么办?

它还显示了该内存消耗的确切数量的细分。 这里有各个部分,它们很复杂,我们将进一步讨论它们,但是现在我们可以注意到主要的事情-这些是Java Heap,我们的Java对象,并且所有其他内容都更加复杂。
还有什么重要的? 对于各种测试和各种外部条件,记忆是一件非常敏感的事情。 也就是说,必须在相同条件下尽可能执行所有测试。 显然,理想情况下,这应该是一台设备,因为内存取决于Android的版本。 只要回顾一下四肢和五肢之间的差异就足够了。 这取决于屏幕的尺寸或分辨率,因为屏幕尺寸越大,闯入的内容越多,则需要花更多的内存来绘制全部内容。 分辨率越大,位图占用的像素就越多,并且需要更多的内存来存储它们。
应用程序场景也会影响测试。 您可以阅读文字,也可以滚动浏览一堆图片。 很明显,哪里会有更多的内存。
另一个重要的事情是设备上的负载。 也就是说,您可以拥有所有相同的东西,但是在一种情况下,您的应用程序是唯一适合您的应用程序,而在另一种情况下,您有一堆应用程序在后台执行某些操作,下载内容,将其删除,在前台运行,与此同时,您的内存仅被压缩了,因为您需要将其分配给其他应用程序。 因此,理想情况下,最好先删除所有其他可用的应用程序,而不是您自己的所有其他应用程序。 您所能达到的一切,然后杀死。 只是在这种情况下,PSS一定会感谢您,因为不需要在进程之间弄乱内存。

例如,您可以获取并查看有关可用内存,已占用内存的当前信息。 他会带给您类似标语的字样:“这里我有那么多可用内存,那么多缓存内存,那么多占用内存。” 而且,如果您有200-250兆字节的空闲内存供您所爱,那么这很有可能,那么没有任何事情会影响您的测试。
也许现在有人问“为什么我需要所有这些?” 这是一个突破者,在此我还要说一下所有这一切的动机。
首先,即使您现在不想在Android Go下执行任何操作并认为它已经死了,它也有可能发展起来,来到您身边,在某个时候您将不得不处理所有这些问题。
我认为非常重要的第二件事是您可以从内存中进行回归测试。 也就是说,您只需编写一个脚本即可运行该应用程序,执行dumpsys,进行此类测量并观察这些指标在版本之间如何变化。 可以在几个小时内编写出这样的脚本,可以将基础结构配置更长的时间,但是在我看来,这是一件好事。
如果我们谈论Android Go的细节-我们在对抗内存方面的第三点-那么会有一些好消息。 首先,没有人真正要求您遵守这些限制。 也就是说,您可以按原样使用该应用程序,并通过Android Go将其放在设备上,一切都很好。 问题在于用户很可能会删除您,因为您占用了大量空间。 而且,您的应用程序可能运行缓慢并具有大量内存,是的。 但是到目前为止,没有人禁止它,因为否则,除了Android Go上的Google应用程序之外,没有其他应用程序。 但是,如果事情进一步发展,那么很多人将适应这种情况,那么最终,您的应用程序可以在Android Go发行中简单地降低,或者您可以向Alert展示用户如何在其Android Go智能手机上安装该应用程序。 :“伙计,该应用无法在Android Go上正常运行。 也许您不会放它?”
还有一点-您可以手动将Android Go设备从Google Play中排除,也就是说,该应用程序无法安装在Android Go设备上。 不久前就出现了。
Google也足够聪明,报告标题中显示的50兆字节不是固定数字,它取决于设备的分辨率,屏幕尺寸以及应用程序的类型。 例如,我认为游戏分配了115兆字节。 原则上,这是可以理解的。

如果我们直接谈论此测试该怎么办? 还有一点,特别是我们非常关心的一点-使用预设。 供应商制造新手机时,通常会在其中放置一些预安装的应用程序。 特别是,我们非常参与其中,问题在于它们运行诸如兼容性测试套件之类的东西。 这些是Google测试,它们运行它们。 而且,如果您的应用程序不符合这50兆字节的要求,那么一切就不好了,并且您的应用程序无法预装在这样的设备上。
不幸的是,Google的测试不是来自开源的,我不能告诉他们,它们是在NDA之下的,但是Google的优秀开发人员写了一篇有关Android Go的文章,从原则上讲,有足够好的建议
也就是说,一切都是陈旧的。 我们启动该应用程序。 我们等待5秒钟以加载所有内容。 我们执行dumpsys,写入TOTAL值,执行很多次,得到结果。 一切都非常简单和司空见惯。

唯一的事情是,他们没有在文章中考虑到这么小的功能,或者也许没有谈论它-发生在另一个过程中的事情,并且他们经常这样做是为了解决包括内存消耗在内的问题。
谁认为这对Android Go有好处? 谁认为这不好? 勇敢

问题是,是的,这很不好,因为最后,您消耗的应用程序内存将计入所有进程。 如果我们创建一个没有任何内容的空进程,并使用该特定进程的dumpsys,我们将看到它占用了7兆字节。 5到8兆字节-这是创建进程的开销。 因此,当我们争夺每兆字节以将其全部压缩为50时,这样的事情就非常糟糕了。 特别是,假设Yandex具有最流行的Yandex.Metrica库,它在不同的过程中也可以工作,这也会给我们带来痛苦。

因此,例如,如果有一些外部库,您可以简单地说:“ Dude,请在主要过程中进行操作。 我同意这可能会比较慢,但不会耗尽不必要的内存。” 因此,这也是一个微妙的地方。

如果我们谈论内存消耗,那么让我们继续进行到那里。 我们执行一个空项目,运行此dumpsys,启动此业务,然后我们看到已经占用了23兆字节(50兆字节)。 空的“你好,世界!” 没有任何内容,只需激活文本即可。 真可悲。 认识到我们可以直接影响Java Heap这样的参数,这使我们更加难过,也就是说,这些直接是我们可以显式跟踪的Java对象,我们可以删除,减少它们并至少以某种方式进行交互。
而且很难与整个过程正常交互,因为这是任何框架代码,并且直接来自Java,您根本没有常规工具来了解如何使用所有这些代码。 但是好消息是我们可以间接影响整个事情,所以让我们谈谈其中存在什么。

什么是Java堆是可以理解的。 什么是原生堆也是很合乎逻辑的假设。 这些是相同的分配,只是肯定的分配。 它们来自框架以及您的本机库,.so文件等。
代码与代码存储直接相关。 这是您的.dex的大小,这是您的.so,这些是资源,mmap文件等。 也就是说,代码越少越好。 通常适用于所有事物的最简单的事实。
堆栈是Java / C ++线程的堆栈。 也就是说,每个线程都有自己的调用堆栈,因此每个线程都会创建一个特定的内存区域来存储整个内容。
图形是UI渲染。 绘制了部分存储的位图以及与之相关的位图。
私人他人,系统-这是我们根本无法影响的东西,实际上,是所有其他不是很容易分类的东西。

如果我们谈论本机库,那么,假设您可以使用一个空的应用程序...您可以使用我们拥有的常规应用程序并从中获取dumpsys,请注意它需要146兆字节。 而且,如果您去剪切某些东西……尤其是,我拿到并看到了两个最大的本机库,我们总共有15 MB,然后使用dumpsys,您可以很容易地看到我们已经从本机堆和从代码。 也就是说,通过这种简单的手势,我们为自己节省了约35兆字节。 还算不错

流。 让我们进行最简单的测试。 有一个空的应用程序,有一个空的应用程序,我们在其中进行一个循环,该循环将执行新的Thread(),在其中休眠五秒钟,然后启动该线程。 您会看到在这种情况下,堆栈得到了极大的补充。 也就是说,我们可以影响整个事情,但是可以间接地减少Java代码中的线程数。 也就是说,通过Java对象,包括影响其他元素中的所有这些位置。

如果继续谈论线程,那么您可以轻松查看线程的用途以及它们在应用程序中的作用。 有不同的工具。 您可以使用相同的systrace,也可以仅使用控制台来查找进程的ID,并根据系统中的线程来获取ps。
如果您做得很好,并使用各种ThreadFactory来命名线程,那么您可以理解应该拥有的东西,不应该拥有的东西,从而减少整个事情,因为在应用程序中拥有100个线程特别没有意义。
还有什么可以做的? 有一组著名的手风琴技巧:监视泄漏,使用池,在不需要时不要创建对象,所有这些都是胡说八道。 太好了
您的应用程序消耗多少内存与内存大小之间有很好的相关性。 也就是说,您的应用程序越大,它将占用的内存就越多,因此,以一种简单的方式,可以减少APK的重量,减少.dex的重量,减少.so,删除所有可以删除的内容。
. , , , . , ? — — , . , , . . — .

dumpsys, , , . , , View, WebView, Assets, .

, , , , , SharedPreference SQLite - , , , .

, , Assets. , , – . 1,5 . -, , . .

— WebView. , WebView, , dumpsys, 100 , . , , - , , 300 — . , WebView , . -.

Google . . WebView, Google, - . WebView. .

Google Go, Android Go-. , - layout , . , , , Chrome Tabs, Chrome . .
Android Go, ? , Android Go, .

有几种方法。 -, , , Android Go . , , . , , , - build , - , , - . APK, , — uses-feature «low-memory», APK.
, , Android Go. Google. , , Go- .
, ? , , - , : «, - . ». . , , , , , - , , - . , , , , Google, Google , . , , , Android Go , , .
, , , -. .

, 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 . .

. build- -. densitySplit, , resConfig, . , , — . ProGuard . , ProGuard , , , , , stacktraces.
. , , Android Go- .
- 64 . : «, ». 14 , 4 , 60 . , . . , . — , , , , . , , , Android Go, . 10 , APK , , . , , .
, — . , . , , - , , . . , , . .