liujiangchuan / liujiangchuan/BlogAndroidCN

Android内存优化总结(博客搬家)

Open
#1 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

good first issue
Dominant language
No language data
Stars
1
Forks
0
PR merge metrics
No merged PRs in 30d

Description

### 以下内容本人于2015/04/02 20:34在“OhwYaa|东软知识社区”平台首发,现整理到个人博客中。原址仅内部公开:https://www.ohwyaa.com/neusoft.com/blog/50ab7b9d-5d7a-47d4-8c0b-00eb6d20c503/view/text

中国移动“和阅读”项目已启动5年多,我进入该项目组时是正在开发v3.0版本,项目的框架结构与基础功能已趋于稳定,随着客户不断提出新的需求,我们也在追求更高的标准和更优化的产品,为用户打造更时尚、便捷的随身阅读新体验。

随着新功能的不断设计和开发,业务逻辑逐渐复杂和庞大,对客户端性能也带来了极大的挑战,这使开发人员需要更加深入了解Android系统的特点及其优化方法。结合对项目的优化经验,在此做出总结与分享,分3个部分说明,分别为:布局优化、代码优化和图像优化。

**1. 布局优化**

(1) 抽象布局标签,使用,, 等标签进行布局;
(2) 减少嵌套层次,多使用RelativeLayout布局;
(3) 使用ListView缓存机制;
(4) 不要给布局写无用的参数,例如RelativeLayout,写layout_weight属性;
(5) 如果LinearLayout用于嵌套的layout空间计算,它的android:baselineAligned设置为false,可以加速layout计算;
(6) 尽量避免嵌套的使用layout_weight,那样会影响执行效率;
(7) 如果为rootView设置了背景,那么会先用Theme指定的背景绘制一遍,然后才用指定的背景绘制,这叫做"overdraw",可以通过theme的background为null来避免;
(8) 优化图片资源,尽量使用.9图片;
(9) 使用hierarchy viewer调优工具,查看布局measure、layout、draw的时间。

**2. 代码优化**

(1) 字符串拼接用StringBuilder代替String;
(2) 数据类型尽可能选择占用空间小的;
(3) 了解弱引用、虚引用;
(4) 优化算法,尽量不用递归;
(5) 尽量少的声明全局变量;
(6) 声明全局静态变量,一定要加final声明;
(7) 声明非静态的全局变量,最好不要初始化任何值,在使用到的地方,在进行初始化;
(8) 函数中若干次使用全局变量,应该将全局变量赋值给本地变量,然后直接使用本地变量;
(9) 能用Int,不要使用浮点数;
(10) 能用乘法不用除法,用位移更好;
(11) 尽量避免使用geter和setter方法;
(12) 在Activity的onCreate函数中,尽量做少的事;
(13) 在Activity中声明的静态数组或者静态代码块,重构到单独的一个类里;
(14) Activity启动后开始进行异步线程的加载,最好delay一下再开启线程;
(15) 对于存在于集合中的Bean对象,尽可能少的声明变量。能int就不要用long,声明的string等复杂变量,最好不要进行初始化;
(16) 使用线程,一定要给它传一个名字,然后需要定义线程的优先级;
(17) 在使用集合的时候,优先选择SparseArray,(代替HashMap)。Java 中每个类(包括匿名内部类)都占用至少 500字节左右的代码;每个类的实例会在 RAM 中占用大约 12 ~ 16 字节的内存;每向 HashMap 中添加一个 Entry 时,新生成的 Entry 占用大约 32 个字节;
(18) 尽量避免使用枚举,枚举类型 Enum 会比静态常量占用更多的内存;
(19) 工具方法尽量写成是静态方法;
(20) 线程间同步尽量使用开销小的同步锁;
(21) 在使用集合类的时候,如果已知数据的规模,在初始化的时候,就设定好默认大小;
(22) 私有内部类访问外部类的私有变量,要将变量修改为包继承权限;
(23) 对于开销大的算法,且不止是执行一次的,要使用缓存策略;
(24) 避免在绘制或者解析布局的时候,分配对象,例如onDraw方法;
(25) 用FloatMath代替Math;
(26) 记得关闭启动的服务;
(27) 当服务中的任务完成后,要记得停止该服务。可以考虑使用 IntentService,因为IntentService 在完成任务后会自动停止;
(28) UI不可见时释放资源;
(29) 在 onStop 中关闭网络连接、注销广播接收器、释放传感器等资源;
(30) 在 onTrimMemory() 回调方法中监听TRIM_MEMORY_UI_HIDDEN级别的信号,此时可在 Activity 中释放 UI 使用的资源,大符减少应用占用的内存,从而避免被系统清除出内存。内存紧张时释放资源。另:尽管系统主要按照 LRU 中顺序来杀进程,不过系统也会考虑程序占用的内存多少,那些占用内存高的进程有更高的可能性会被首先杀死;
(31) 确定你的程序应该占用多少内存,可以通过getMemoryClass()来获取你的程序被分配的可用内存,以 M 为单位。你可以通过在 标签下将 largeHeap 属性设为 true 来要求更多的内存,这时通过 getLargeMemoryClass() 方法来获取可用内存。大部分应用程序不需要使用此功能,因此使用该标签前,确认你的程序是否真的需要更多内存。使用更多内存会对整个系统的性能产生影响,而且当程序进入 LRU时会更容易首先被系统清理掉;
(32) 谨慎使用第三方类库;这些外部类库可能原先并非针对移动平台,因此未进行过优化,在使用前应注意。另外尽量不要因为一两个特性而使用一个体积很大的类库;
(33) 使用 ProGuard 移除无用的代码并重命名一些类、字段、方法等,使你的代码更紧凑,节省内存空间;
(34) 使用多个进程。如果程序需要执行大量的后台工作,可考虑将程序分为两个进程,一个进程负责 UI,另一个进程负责后台任务。比如音乐播放器。在决定是否使用多进程前,应注意,一个不执行任何任务的空进程至少也要占用 1.4 MB内存。另外要注意进程的相互依赖性,比如如果将ContentProvider 放在 UI 进程中,而后台任务进程也需要调用 ContentProvider,就会导致 UI 进程一直保留在 RAM 中。

**3. 图像优化**

图片资源的使用不当经常会造成OOM的问题,尤其在低端机型内存较少的情况下。
(1) 及时回收。
正确使用 Bipmap,避免浪费内存;调用recycle方法主动回收资源。代码示例:
```
if(null != bitmap && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap= null;
}
```
(2) 适当压缩。
如果你的ImageViwe 的尺寸只有50 * 50,那么没有必要将一张1280 * 720 的图片整个加载入内存;对图片进行适当的压缩。代码示例:
```
BitmapFactory.OptionsnewOpts = newBitmapFactory.Options();
newOpts.inPreferredConfig= Config.RGB_565;
newOpts.inJustDecodeBounds= true;
Bitmapbitmap = BitmapFactory.decodeFile(srcPath,newOpts);
newOpts.inJustDecodeBounds= false;
intold_w = newOpts.outWidth;
intold_h = newOpts.outHeight;
intnew_w = targetWidth;
intnew_h = targetHeight;
intbe = (int) ((old_w / new_w + old_h /new_h) >> 1);
if(be <= 1) {
be= 1;
}
newOpts.inSampleSize= be;
bitmap =BitmapFactory.decodeFile(srcPath,newOpts);
```

本项目经过一轮仔细的优化后,在测试机上,内存占用情况从平均68.5M降低到平均48.5M,有明显的优化效果。优化是一个需要持之以恒要去完善的任务,希望每个开发者都对性能优化有所了解,在开发过程中除了实现需求和功能之外,多去思考如何写出更漂亮的代码,为项目锦上添花。

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue body contains the full Android memory-optimization article and links to its original internal publication. Start by comparing that source with the intended blog location; the issue does not name a target file, test, or specific missing change. Done would require a clearly identified publication or content-update scope, which is not stated here.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java
Domain
content, documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.