Android学习——内存管理技巧

Android内存管理技巧

1.使用Service的风险

如果应用程序当中需要使用Service来执行后台任务的话,请一定要注意只有当任务正在执行的时候才应该让Service运行起来。另外,当任务执行完之后去停止Service的时候,要小心Service停止失败导致内存泄漏的情况。
当我们启动一个Service时,系统会倾向于将这个Service所依赖的进程进行保留,这样就会导致这个进程变得非常消耗内存。并且,系统可以在LRU cache当中缓存的进程数量也会减少,导致切换应用程序的时候消耗更多性能。严重的话,甚至有可能会导致崩溃,因为系统在内存非常吃紧的时候可能已无法维护所有正在运行的Service所依赖的进程。
为了能够控制Service的生命周期,Android官方推荐的最佳解决方案就是使用IntentService,这种Service的最大特点就是当后台任务执行结束后会自动停止,从而极大程度上避免了Service内存泄漏的可能性。
注意:
让一个Service在后台一直保持运行,即使它并不执行任何工作,这是编写Android程序时最糟糕的做法之一。

2.当界面不可见时释放内存

当用户打开了另外一个程序,我们的程序界面已经不再可见的时候,我们应当将所有和界面有关的资源进行释放。只需要在Activity中重写onTrimMemory()方法,然后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发之后,就说明用户已经离开了我们的程序,那么此时就可以进行资源释放操作了。

3.当内存紧张时释放内存

onTrimMemory()方法还有很多种其它类型的回调,可以在手机内存降低的时候及时通知我们。我们应该根据回调中传入的级别来去决定如何释放应用程序的资源:

  • TRIM_MEMORY_RUNNING_MODERATE
    表示程序正常运行,不会被杀掉。但内存已经有点低了,系统可能会开始根据LRU缓存规则来去杀死进程了。
  • TRIM_MEMORY_RUNNING_LOW 表示程序正常运行,不会被杀掉。但内存已经非常低了,我们应该去释放掉一些不必要的资源以提升系统的性能,同时这也会直接影响到我们应用程序的性能。
  • TRIM_MEMORY_RUNNING_CRITICAL 表示程序正常运行,但系统已经根据LRU缓存规则杀掉了大部分缓存的进程。我们应当尽可能地去释放任何不必要的资源,否则系统可能会继续杀掉所有缓存中的进程,并且开始杀掉一些本来应当保持运行的进程,比如说后台运行的服务。

以上是当我们的应用程序正在运行时的回调。

如果我们的程序目前是被缓存的,则会收到以下几种类型的回调:

  • TRIM_MEMORY_BACKGROUND 内存已经很低了,系统准备开始根据LRU缓存来清理进程。这个时候我们的程序在LRU缓存列表的最近位置,是不太可能被清理掉的,但这时去释放掉一些比较容易恢复的资源能够让手机的内存变得比较充足,从而让我们的程序更长时间地保留在缓存当中,这样当用户返回我们的程序时会感觉非常顺畅,而不是经历了一次重新启动的过程。
  • TRIM_MEMORY_MODERATE 内存已经很低了,并且我们的程序处于LRU缓存列表的中间位置,如果手机内存还得不到进一步释放的话,那么我们的程序就有被系统杀掉的风险了。
  • TRIM_MEMORY_COMPLETE 内存已经很低了,并且我们的程序处于LRU缓存列表的最边缘位置,系统会最优先考虑杀掉我们的应用程序,在这个时候应当尽可能的把一切可以释放的东西都进行释放。

4.避免在Bitmap上浪费内存

磁盘缓存和内存缓存

5.使用优化过的数据集合

在这里插入图片描述
SparseArray指的是稀疏数组(Sparse array), 所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。
SparseArray是android里为<Integer ,Object>这样的HashMap而专门写的类,目的是提高效率,其核心是析半查找函数(binarySearch)。

6.了解内存的开支情况

  • 使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中我们应当尽可能地不使用枚举
  • 任何一个Java类,包括内部类、匿名类,都要占用500字节的内存空间
  • 任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程度上影响内存的
  • 在使用HashMap时,即使你只设置了一个基本数据类型的键,比如说int,但是也会按照对象的大小来分配内存,大概是32字节,而不是4字节。因此最好的办法就想上面说的,使用优化过的数据集合。

7.反抽象编程理念

在面向对象的世界里,使用抽象编程是一种被崇尚的编程习惯,使用抽象编程在代码的维护和可扩展性方面都会提高很多,但是,在Android上使用抽象会带来额外的内存开支,因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是却也要映射到内存当中,不仅占用了更多的内存,在执行效率方面也会有所降低。

所以,在Android世界里,一切以性能、高效为宗旨,请不要滥用抽象编程。

8.避免使用依赖注入框架

使用一些依赖注入的框架后,代码可能是这样的:

在这里插入图片描述
这些框架为了搜寻代码中的注解,通常都需要经历比较长的初始化过程,并且可能将一些你用不到的对象也一并加载到内存中。
这些用不到的对象会一直占用着内存空间,可能要过很久才能得到释放。

9.使用ProGuard混淆代码

ProGuard通常大家都会认为是-一个混淆代码的工具,但是除了混淆之外,它还具有压缩和优化代码的功能。ProGuard会对我们的代码进行检索,删除一些无用的代码,并且会对类、字段、方法等进行重命名,重命名之后的类、字段和方法名都会比原来简短很多,这样的话也就对内存的占用变得更少了。
在这里插入图片描述
导入进app文件下
在这里插入图片描述
之后进入build文件修改minifyEnable为true,再同步,则生成的apk即被混淆。

10.使用多个进程

想要实现多进程的功能也非常简单,只需要在清单文件的应用程序组件中声明一个android:process属性就可以了,比如我们说希望播放音乐的Service可以运行在一个单独的进程当中:

<service android:name=".PlaybackService"
		android:process=":background"/>

猜你喜欢

转载自blog.csdn.net/UUUUUltraman/article/details/89522448