当前位置: 移动技术网 > IT编程>移动开发>Android > Android开发中常见内存问题与优化避免

Android开发中常见内存问题与优化避免

2019年04月18日  | 移动技术网IT编程  | 我要评论

cf宝石怎么镶嵌,小娇和小婉,赏雪杂感李白

android开发中常见内存问题与优化避免,比起前几年,现在的 android 设备拥有更大的内存。但是,即使现在可以使用更多的内存,也是有一个上限的,具体大小和各个厂商的设置有关。如果内存使用不当,还是会影响到app的性能。内存问题主要有两类,一是内存溢出,二是内存泄漏。解决内存问题,主要靠借助工具检测分析,然后做代码优化。

一、android 应用开发中的内存问题

1.1 单个进程可用内存限制

目前的 android 设备,动辄4g、6g甚至8g内存,但是,android设备的内存再大,每个应用可以使用的内存大小也是有限制的,具体可以使用的最大内存和各大厂商的出厂设置有关。
可以通过adb 查看应用可以使用的最大内存:

adb shell cat /system/build.prop
// ...
dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=256m
dalvik.vm.heapsize=512m
// ...

上面的设备是 galaxy s7,可以使用的最大内存为512m,这需要在 manifest.xml 中 application 节点添加 android:largeheap=”true”,否则,最多只能使用256m。
也可以直接查看它们的值:

adb shell getprop dalvik.vm.heapgrowthlimit
256m
adb shell getprop dalvik.vm.heapsize
512m
adb shell getprop dalvik.vm.heapstartsize
8m

现在的应用,对于图片质量的要求越来越高,动辄几百k,甚至上m一张图片,对于需要加载大量图片的应用来说,256m内存,分分钟就上去了。256m说大不大,说小不小,但是使我们的应用尽量少用内存总不会错。因为占用内存越大,gc频率就可能越高,然后就会出现卡顿的现象。

1.2 内存溢出

内存溢出就是你要求分配的内存超出了能给你的,系统不能满足需求,于是产生溢出,简单来说就是,需要的内存超过了可以使用的最大内存值。一旦出现内存溢出,就会报 out of memory 的错误,app crash。 导致内存溢出的原因有很多,这里根据项目中曾经出现过的做一个总结:

直接加载原图
需要浏览大图的时候,使用 imageview 直接加载原图;或者需要加载bitmap时直接读取了原图大小。 使用图片背景
app的每个页面都使用一张图片作为背景(表示对图片背景深恶痛绝),导致内存暴增,然后oom。 接口处理太多数据
有接口需要将文件如图片等进行urlencode为字符串,然后通过接口上传到服务器,然后一次处理多个文件,导致oom。 内存泄露并堆积
activity和对话框等内存泄露,得不到释放,导致oom。

1.3 内存泄漏

内存泄漏是指程序在申请内存后,无法释放已申请的内存空间。内存泄露和内存溢出是有区别的,内存溢出必然导致oom,而内存泄露则可能导致内存溢出。内存泄露的原因有很多,下面是比较常见的几个原因:

静态变量导致内存泄露 非静态内部类导致内存泄漏,如handler等,持有activity的引用无法释放
activity中非静态内部类如handler等,并不是总会引起内存泄漏,只是可能。 线程未完成任务导致activity不能释放,内存泄漏,如thread、asynctask、timer和timertask等。 webview导致内存泄漏 错误使用单例模式(持有activity的context) 资源未关闭造成的内存泄漏(io操作,操作) 属性动画造成内存泄露 未取消注册或回调导致内存泄露

二、内存优化方法

内存优化可以从四个方向进行:开源,节流,复用,回收。开源,即必要的时候使用largeheap、多进程等,使应用可以使用更多的内存,需要慎重考虑,因为largeheap和多进程引进的问题比它们带来的优化更多。节流,减少不必要的内存分配,这个需要在有一个良好的编码习惯,是每个开发者应该尽力做到的。复用,顾名思义,就是可以复用的对象就不要重复创建,如listview 使用viewholder进行优化就是复用了view。

2.1 开源

让应用使用最大内存

让应用可以使用最大内存,只需要在 manifest.xml 中设置 android:largeheap=”true” 即可。这个设置效果还是很明显的,如需要加载一张原图,没有添加这个属性之前,使用bitmap.setresources等方法时应用可能直接就 crash 了,而增大应用可用内存后,加载一张原图可能就不会导致 crash 了。

多进程

尽量不要使用多进程,因为多进程带来的问题可能比其带来的优化还要多,如果不了解,不熟悉,就不要使用。但是,当有需要的时候还是要考虑一下多进程,需要多进程时,就需要先了解下ipc。多进程如何实现,有什么坑,这里就不多做描述,毕竟总结起来比内存优化篇幅长多了。

2.2 节流

节流的含义是减少不必要的内存分配,从int还是long类型选择,到bitmap加载图片,到是否需要将某个属性升级为成员变量,可以从各个方面去考虑、优化。下面列出几个可以优化的点:

采用合适的数据类型 使用 bitmapfactory.options 加载合适尺寸大小和合适位深的图片 避免使用图片背景,如果必要,看看是否可以使用颜色背景和更小的图片一起替换 使用 viewstub 延迟加载那些可能用不到的view 避免使用activity作为全局变量,如果有必要,看看是否可以使用application的context代替 如果需要,使用stringbuilder代替字符串拼接

2.3 复用

使用viewholder优化listview ( recyclerview代替listview是一个不错的选择 ) 使用三级缓存的图片加载工具显示图片,如glide等

2.4 回收

不再需要的对象就要及时回收,一般来说gc会帮我们擦屁股,但是有些对象仍然需要主动释放,或者一些不规范的代码会导致对象无法被gc回收。

及时回收不再使用的bitmap 根据需要修改象的引用类型:strong reference,softreference,weakreference,phantomreference 注意 handler、线程、timer 等异步工具类的使用,防止内存泄漏 及时关闭 closeable,如 inputstream 和 outputstream,数据库的cursor等

三、内存问题检测与定位

有很多工具可以检测发现内存问题,静态代码分析工具 lint,运行时发现代码问题的 strictmode,专门用于内存泄漏检查的 leakcanary。

3.1 lint

lint 是一个很好的代码分析工具,在我们编码阶段就可以给予我们很“友好”的优化提示,把 bug 拦截在编译之前。

lint 是android studio 提供的 代码扫描分析工具,它可以帮助我们发现代码结构/质量问题,同时提供一些解决方案,而且这个过程不需要我们手写测试用例。

除了发现代码结构/质量问题外,lint 还可以发现和删除没有使用的资源,从而减少apk的体积。

3.2 严格模式

strictmode类是android 2.3 (api 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题,以达到提升应用响应能力的目的。举个例子来说,如果开发者在ui线程中进行了网络操作或者文件系统的操作,而这些缓慢的操作会严重影响应用的响应能力,甚至出现anr对话框。为了在开发中发现这些容易忽略的问题,我们使用strictmode,系统检测出主线程违例的情况并做出相应的反应,最终帮助开发者优化和改善代码逻辑。

严格模式的接入比较简单,但对于android的性能优化(内存泄漏和anr)有非常大的帮助。

3.3 leakcanary

在实际的项目中,其实没有用到leakcanary,但是各种书,博客都在介绍 leakcanary,想必也是一个很好的工具。leakcanary的接入也不难。

3.4 android profiler 内存分析

android profiler 是 android studio 3.0 版本代替原有的android monitor的性能分析工具。

四、总结

导致 oom 的问题大多是内存泄漏的问题,特别是activity无法释放的问题尤为严重。通过各种工具分析定位,比较容易找到问题的代码,从而改正它。而除了内存泄漏,其它一些问题则是比较难发现,因为这些问题隐藏在代码间。要做到心中有数,就要有一个良好的编码规范,该分配创建对象时创建,该复用的复用,该回收时回收。内存优化是一条很远路,优化在每一行代码之间,只有时刻保持警觉,严格要求自己,才能写出健壮的代码。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网