购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.3.2 减少数据的加载

想要减少加载进Java堆的数据,我们可以通过减小缓存大小、按需加载数据、转移数据这几种方式来实现。

1.减小缓存大小

业务开发中不可避免地需要用到很多缓存,缓存是一种用空间换时间的方案,可有效地提升系统性能。缓存使用得多,内存占用就多,减少缓存的使用,自然也能减少内存的占用。但是减少缓存的使用会降低用户体验,所以在减少缓存的使用时需要综合评估业务的体验、OOM、业务使用频率等多方面因素。具体该怎么操作呢?就拿LruCache(Least Recently Used Cache,最近最少被使用缓存)来说,它是我们使用最多的缓存之一,要优化LruCache这类缓存,我们需要考虑如下两点:

❑缓存的大小是多少?

❑缓存中的数据何时清理?

先看第一个问题。我们需要在LruCache构造函数中设置LruCache的容量,网上很多文章都提到默认传入最大可用堆内存的12.5%,这样设置其实并不太准确。我们需要评估业务的重要性和业务使用频率。如果是重要并且使用频率高的业务缓存,这里的容量多设置一些也能接受。同时,我们还需要评估当前的机型,如果是只有256MB可用堆内存的低端机,这里设置为12.5%(即32MB)就有点多了,可能会对整个应用的稳定性产生影响。那么到底应该设置为多少?建议综合机型、业务并充分考虑后再设置,这里没有绝对的标准,需要应用的开发者结合实际场景和业务进行评估。

再来看第二个问题。缓存中的数据何时清理呢?LruCache自带了缓存清理的策略,这个缓存的容量满了之后,就会清理最后一个最近未被使用的数据。除了这个清理策略之外,我们可以再多增加一些策略,比如当Java堆内存的使用达到阈值(如80%)时就清理LruCache的数据。

除了LruCache之外,常用的缓存还有List、Map等。在做内存优化时,我们需要考虑如下问题:

❑应用运行时所占用的内存会有多大?

❑是否会因为缓存过大导致内存异常?

❑如何及时清理缓存?

2.按需加载数据

按需加载数据指的是只有真正需要用到的时候才去加载数据。Android系统中用到大量按需加载的策略。比如前面提到的mmap函数申请的其实是虚拟内存,只有真正需要存放数据时才会去分配并映射物理内存。在应用开发中,使用按需加载数据的策略能节约不少Java堆内存。

在项目开发中,也有很多场景用到该策略,比如我们通常会在项目中将各种全局服务注册到一个服务容器中,再通过服务的接口将各个业务的能力暴露出去,达到解耦的目的。很多情况下,我们会在程序启动或者业务初始化的时候进行注册。但如果采用按需加载数据的策略,将注册逻辑延迟到真正需要使用该服务的时候再进行,便能实现对系统性能的优化。除此之外,对于应用启动时的各种预加载,我们也可以思考是否可以在真正使用时再进行加载。按需加载数据的案例有很多,这里就不一一列举了。

3.转移数据

我们知道,Java堆的大小是有限制的,主流机型下的可用大小只有512MB。那如果我们将需要放入Java堆的数据转移到其他地方,是不是就可以突破512MB的限制了呢?实际上确实可以这样做,转移数据的方式主要有以下两种。

将Java堆中的数据转移到Native中 :针对这一优化方案,Bitmap是一个很经典的案例。在Android 8以前的版本中,Bitmap是算入Java堆的空间的,Android 8及之后的版本却将Bitmap放入了Native中。这一策略极大地增加了Java堆的可用空间。在Android 8之前,Fresco这款图片加载工具也采用过将Bitmap的创建放在Ashmem匿名共享内存中的方案来优化Java堆内存。可以看到,Android系统或者Fresco框架都是基于将原本存放在Java堆中的数据转移到Native中这一思路来优化Java堆内存的,所以我们在做Java堆内存优化时也可以采用这样的思路。比如说,我们可以将需要读取大数据的业务下沉到Native层去做,包括网络库、业务的数据处理等。即使是Bitmap,在Android 8以前的版本中,也是可以通过Native Hook等技术手段转移到Native中的。

将当前进程中Java堆的数据转移到其他进程中 :每个进程的Java堆都是固定的,但是我们可以将应用设计成多进程模型,这样就有多个可用的Java堆空间了。我们可以选择将比较独立的业务放在子进程中,如需要小程序、Flutter、RN、Webview等容器承载的业务,当我们把这些业务放在独立的子进程中后,不仅可以减小主进程中Java堆的大小,还能降低主进程中因为这些业务导致的内存泄漏、Crash等性能问题的出现概率。 acSip/DSa3lOzxfstjOrYrhOfMR0DQYhcWn7We7EpjYGkfMJvsPJOyN8sEuqTSf5

点击中间区域
呼出菜单
上一章
目录
下一章
×