Android减少内存占用专题Android开发经验:不要动不动就分配内存2011-03-21开发Andorid应用的开发者都知道,要尽量减少new关键字的使用,因为在手机上GC释放一次内存是一件恐怖的事情,如果你查看一下调试记录,你会发现GC释放内存时有时会花上几百毫秒的时间。
可以想象,如果你开发的是游戏,这时你的FPS会下降到多少。
虽然这个原则大家都知道,我们还是会看到一些开发者会出现类似问题,这又是为什么呢?呵呵,其实这是一些隐式的对象创建在作怪,看看以下代码:原则1:如果可能,请不要使用可变参数当外部调用时:系统会自动创建一个临时的数组对象,类似于:如果该函数经常被调用,则会极大增加GC的压力。
所以,如果可能,请不要使用可变参数。
原则2:如果可能,请用StringBuilder代替字符串的相加我们来看一段代码:系统会将这句翻译成为如下格式:这本身没有什么问题,但如果是如下就有意思了:这段代码等效于:这样是不是悲剧,本来StringBuilder被无意义的重复创建了多次,期间还在数字转换到文本时创建了String,所以请直接使用显示的StringBuilder来链接字符串。
原则3:尽量将不变的东东设置为常数,特别是字符串较有效的办法是,你的代码可以这样来写:当然,即使这样做了,后续对文本操作(如整数到文本转换)仍然是一件费时费力的或,原因是JAVA中,String 是只读的,任何String的内容操作均隐含了new关键字。
作者在实际工作中只好采取了更笨笨的办法,自己实现了一个GString类来替代常用的文本操作,其原理时使用预分配的字节内存,只在需要时才转换为String对象。
Android进阶:性能优化篇2011-05-11一、图片载入过多出现OutOfMemoryError异常在使用Gallery控件时,如果载入的图片过多,过大,就很容易出现OutOfMemoryError异常,就是内存溢出。
这是因为Android默认分配的内存只有几M,而载入的图片如果是JPG之类的压缩格式,在内存中展开时会占用大量的空间,也就容易内存溢出。
这时可以用下面的方法解决:二、统一管理位图资源,适时释放资源三、网络连接往往是耗电量比较大的。
我们可以优化一下在需要网络连接的程序中,首先检查网络连接是否正常,如果没有网络连接,那么就不需要执行相应的程序。
检查网络连接的方法如下:四、网络间的数据传输也是非常耗费资源的,这包括传输方式和解析方式。
看下面的表格:其中Tree Parser是DOM方式解析,Event/Stream是SAX方式解析。
很明显,使用流的方式解析效率要高一些,因为DOM解析是在对整个文档读取完后,再根据节点层次等在内存中进行组织。
而流的方式是边读取数据边解析,数据读取完后,解析也就完毕了。
在数据格式方面,JSON和Protobuf效率明显比XML好很多,XML和JSON大家都很熟悉。
从上面的图中我们可以得出结论就是尽量使用SAX等边读取边解析的方式来解析数据,针对移动设备,最好能使用JSON之类的轻量级数据格式为佳。
五、传输数据经过压缩。
目前大部门网站都支持GZIP压缩,所以在进行大数据量下载时,尽量使用GZIP方式下载,可以减少网络流量。
使用方法如下所示:六、有效管理Service后台服务就相当于一个持续运行的Acitivity。
如果开发的程序后台都会一个service不停的去服务器上更新数据,在不更新数据的时候就让它sleep,这种方式是非常耗电的,通常情况下,我们可以使用AlarmManager来定时启动服务。
如下所示,第30分钟执行一次。
开发过程中应该注意一些细节,并经手机的整体性能和续航都是有很大的局限,很多个优化的细节会对软件产生本质的影响,这些需要引起重视,也要在开发过程中不断积累。
Android内存泄漏调试I2010-07-25一、概述Java编程中经常容易被忽视,但本身又十分重要的一个问题就是内存使用的问题。
Android应用主要使用Java 语言编写,因此这个问题也同样会在Android开发中出现。
本文不对Java编程问题做探讨,而是对于在Android 中,特别是应用开发中的此类问题进行整理。
由于作者接触Android时间并不是很长,因此如有叙述不当之处,欢迎指正。
二、Android(Java)中常见的容易引起内存泄漏的不良代码Android主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存很有限。
如果我们编写的代码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机。
为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。
一方面,如果程序在运行过程中出现了内存泄漏的问题,仅仅会使得自己的进程被kill掉,而不会影响其他进程(如果是system_process等系统进程出问题的话,则会引起系统重启)。
另一方面,Android 为不同类型的进程分配了不同的内存使用上限,如果应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉。
Android为应用进程分配的内存上限如下所示:位置:/ANDROID_SOURCE/system/core/rootdir/init.rc部分脚本正因为我们的应用程序能够使用的内存有限,所以在编写代码的时候需要特别注意内存使用问题。
如下是一些常见的内存使用不当的情况。
(一)查询数据库没有关闭游标描述:程序中经常会进行查询数据库的操作,但是经常会有使用完Cursor后没有关闭的情况。
如果我们查询的结果集比较小,对内存的消耗则不容易被发现,只有在长时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。
示例代码:修正示例代码:描述:以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:来向ListView提供每一个item所需要的view对象。
初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。
当向下滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。
这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。
由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。
ListView回收list item的view对象的过程可以查看:示例代码:修正示例代码:描述:有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。
可以看一下代码中的注释:描述:这种情况描述起来比较麻烦,举两个例子进行说明。
示例A:假设有如下操作我们有一个成员变量obj,在operation()中我们希望能够将处理obj实例的操作post到某个线程的MessageQueue中。
在以上的代码中,即便是mHandler所在的线程使用完了obj所引用的对象,但这个对象仍然不会被垃圾回收掉,因为DemoActivity.obj还保有这个对象的引用。
所以如果在DemoActivity中不再使用这个对象了,可以在[Mark]的位置释放对象的引用,而代码可以修改为:示例B:假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。
对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。
但是如果在释放LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。
如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process进程挂掉。
总之当一个生命周期较短的对象A,被一个生命周期较长的对象B保有其引用的情况下,在A的生命周期结束时,要在B中清除掉对A的引用。
(五) 其他Android应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在onPause()、onStop()、onDestroy()方法中需要适当的释放资源的情况。
由于此情况很基础,在此不详细说明,具体可以查看官方文档对Activity生命周期的介绍,以明确何时应该释放哪些资源。
Android内存泄漏调试II紧接《Android内存泄漏调试I》。
三、内存监测工具DDMS --> Heap无论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方。
Android tools中的DDMS就带有一个很不错的内存监测工具Heap(这里我使用eclipse的ADT插件,并以真机为例,在模拟器中的情况类似)。
用Heap监测应用进程使用内存情况的步骤如下:1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的;2. 将手机通过USB链接至电脑,链接时需要确认手机是处于“USB调试”模式,而不是作为“Mass Storage”;3. 链接成功后,在DDMS的Devices视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息;4. 点击选中想要监测的进程,比如system_process进程;5. 点击选中Devices视图界面中最上方一排图标中的“Update Heap”图标;6. 点击Heap视图中的“Cause GC”按钮;7. 此时在Heap视图中就会看到当前选中的进程的内存使用量的详细情况[如图所示]。
说明:a) 点击“Cause GC”按钮相当于向虚拟机请求了一次gc操作;b) 当内存使用信息第一次显示以后,无须再不断的点击“Cause GC”,Heap视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;c) 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。