Android中的大内存需求-怎么办?

尊敬的读者您好。

今天,我们提请您注意有关Android中内存有效使用的一些材料



享受阅读!

本文重点介绍管理应用程序(例如,浏览器,照片编辑器和PDF查看器)中的内存使用情况的基本技术,在这些应用程序中会发出大量内存请求。

一,一点理论


大多数Android应用程序都在运行时(ART之上运行,该运行时(ART)已经取代了已经过时的Dalvik虚拟机。ART和Dalvik与Java虚拟机(JVM)相似,它们共享相似的设计原理。它们使用两个单独的空间来存储应用程序数据:堆栈和堆。

堆栈内存

Java中的堆栈内存用于存储局部变量(原始类型和对象引用)。每个Java线程都有自己的单独堆栈。与堆内存相比,栈内存相对较小。Dalvik的Java堆栈大小对于Java代码通常为32 KB,对于本机代码(C ++ / JNI)为1 MB。ART和Java出现了统一的堆栈,其大小约为1 MB。

当应用程序选择整个堆栈内存到极限时,将引发错误StackOverflowError。达到堆栈限制的最可能原因是无限递归或方法调用太深。对堆栈存储器的引用始终按LIFO顺序进行(先到先得)。每次调用方法时,都会使用该方法的局部变量将新的框架压入堆栈。方法完成后,将其框架弹出堆栈,并将所有可能的结果值发送回堆栈。因此,第一个问题(无限递归)是一个易于修复的错误,但第二个问题需要一些重构,其中包括部署递归方法调用并将其转换为循环。

堆内存

虚拟机使用Java中的堆内存来分配对象。每当创建对象时,它都会在堆上发生。虚拟机(例如JVM或ART)定期收集垃圾,删除不再引用的所有对象,从而释放内存以分配新对象。
为了确保可用性,Android严格限制了每个正在运行的应用程序的堆大小。堆大小限制因设备而异,并且取决于该设备上有多少RAM。如果您的应用程序达到最大堆大小并尝试分配更多的内存,则会生成错误OutOfMemoryError并终止应用程序。让我们看一些示例来帮助避免这种情况。

堆内存分析


理解应用程序中的内存问题并了解如何使用内存的最重要工具是Android Studio中提供的内存分析器

该工具可以可视化显示您的应用程序随着时间消耗的内存量。您可以在运行的应用程序中拍摄Java堆的快照,记录内存分配操作,并在功能强大的UI中监视堆或此内存分配历史记录。

典型的内存事件探查器会话应如下所示:

  • 我们查看最频繁的内存分配和垃圾收集器通道以识别可能的性能问题。
  • , , , , , . , . , , PdfActivity PSPDFKit .
  • , . , . – , , .


现代垃圾收集器是技术艺术的复杂作品,是多年研究和开发的结果,从学者到专业开发人员,数百人参与其中。但是,仍然必须保持警惕,以防止内存泄漏。

用于检测内存泄漏的示例解决方案是LeakCanary。在测试程序集(开发版本)中时,它将自动发出通知,从而在此程序的UI中为您提供泄漏跟踪率。您今天可以(并且应该)集成它,尤其是因为它并不困难!

当处理活动或Android片段的复杂生命周期时,特别容易引发内存泄漏。这通常发生在开发人员在后台任务或静态变量中强烈引用UI 上下文或其他特定于UI的对象的情况下。引起这种延迟的一种方法是在测试应用程序时主动扭曲设备。

释放内存以响应事件


Android可能需要应用程序分配内存,或者在需要释放内存以执行更关键的任务时直接强制其终止。在此之前,系统将允许您提供不需要的所有内存。在您的活动中,您将需要实现一个接口ComponentCallbacks2。在这种情况下,只要系统内存不足,就会对您的方法进行调用onTrimMemory(),您将可以释放内存或禁用在这种内存不足情况下无法使用的功能。

因此,此类回调在PSPDFKit应用程序中处理。PSPDFKit应用程序的设计是根据内存的有效使用情况进行计算来进行缓存的,因此该应用程序将尽可能平稳地运行。最初尚不知道设备上有多少可用内存,因此PSPDFKit会根据情况调整并在收到有关内存不足的通知时限制内存使用。因此,与PSPDFKit集成的应用程序甚至可以在低技术设备上运行,但由于禁用了缓存,因此性能降低。

大堆


满足高内存需求的前端解决方案之一是为您的应用程序请求大量的Dalvik。为此,您可以android:largeHeap="true"在文件中添加到<application>标记AndroidManifest.xml

如果将该属性largeHeap设置为value true,Android将为您的应用程序创建具有大堆的所有进程。此设置仅适用于本质上无法运行的应用程序,即,它们使用必须同时容纳在内存中的大量资源。

如果只想提高内存使用上限,强烈建议不要使用大堆。应始终优化内存使用情况,因为在内存较小的弱设备上工作时,即使是一大堆应用程序也可能不够用。

检查您的应用程序可以使用多少内存


检查应用程序的堆大小并动态地使代码和可用功能适应这些内存限制,这无济于事。您可以使用getMemoryClass()getLargeMemoryClass()(在启用大堆时)直接在运行时检查最大堆大小

Android甚至支持仅512 MB RAM的设备。确保不要忽视低技术含量的设备!使用方法isLowRamDevice()您可以检查您的应用程序是否在没有足够可用内存的设备上运行。此方法的确切行为取决于设备,但通常在RAM小于1 GB的设备上返回true。您需要确保您的应用程序可以在这些设备上正常运行,并禁用所有在这些设备上使用大量内存的功能。

要详细了解Android如何在内存量较小的设备上运行,请点击此处此处还提供了其他优化技巧。

使用优化的数据结构


在许多情况下,应用程序使用过多内存的原因很简单,即它们不使用最合适的数据结构。

Java集合不能存储有效的原始类型,并且需要打包其键和值。例如,HashMap带有整数的键应替换为优化的SparseArray。最终,您始终可以使用原始数组而不是集合,如果您的集合不可调整大小,那么这是个好主意。

在内存使用方面效率低下的其他数据结构包括各种序列化。是的,确实,XML或JSON格式使用起来很方便,如果使用更有效的二进制格式(例如协议缓冲区),则可以减少内存使用量

所有这些示例,都经过优化以节省内存的数据结构,仅是提示。与重构一样,您必须首先找到问题的根源,然后再进行此类性能优化。

防止记忆改组


Java / Android虚拟机可以非常快速地分配对象。垃圾收集也非常快。但是,在短时间内分配大量对象时,您可能会遇到一个称为“内存搅动”的问题。在这种情况下,虚拟机将没有时间以这种速度分配对象,垃圾收集器将处理它们,并且应用程序将开始变慢,在极端情况下,它甚至会耗尽所有内存。

在这种情况下,Android领域的主要问题是我们无法控制何时进行垃圾回收。潜在地,这可能会导致问题:例如,垃圾收集器在动画在屏幕上展开时正好起作用,并且我们超过了16毫秒的阈值,这确保了帧的平滑显示。因此,重要的是要防止代码中内存的过度分配。

导致内存改组的情况的一个示例是大型对象的分配,例如,onDraw()presentation 方法内部的Paint 在这种情况下,会快速创建许多对象,并且可以开始垃圾回收,这可能会对此视图的性能产生不利影响。如上所述,您应该始终监视内存使用情况,以避免这种情况。

结论


移动设备上的随机存取存储器(RAM)可能是非常有限的资源。如果您的应用程序可以处理相对较大的对象,例如光栅图形(PDF查看器,Web浏览器,照片编辑器)或大型媒体文件(音频或视频编辑器),那么确保应用程序中内存的有效利用就显得尤为重要。遵循这些技巧,您将学习如何创建即使在最强大的设备上也可以在可接受的水平上运行的高质量应用程序。

All Articles