1.节制的使用Service,最好使用IntentService(任务结束会自动停止,避免Service内存泄漏),只有当任务正在执行的时候才让Service运转起来
2.避免创建不必要的对象(StringBuilder和String)
3.对常量使用static final修饰
4.使用增强型for循环语法(ArrayList除外),传统for循环的第二布尽可能简洁
5.重用布局文件,include,merge(减少布局嵌套层数),ViewStub(按需加载,View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate(); importPanel.findViewById())
6.Bitmap(内存消耗大户):
在实例化Bitmap的代码中,一定要对OutOfMemory异常进行捕获,出现异常得到一个默认的bitmap图;
缓存通用的Bitmap对象
有时候,可能需要在一个Activity里多次用到同一张图片。比如一个Activity会展示一些用户的头像列表,而如果用户没有设置头像的话,则会显示一个默认头像,而这个头像是位于应用程序本身的资源文件中的。
如果有类似上面的场景,就可以对同一Bitmap进行缓存。如果不进行缓存,尽管看到的是同一张图片文件,但是使用BitmapFactory类的方法来实例化出来的Bitmap,是不同的Bitmap对象。缓存可以避免新建多个Bitmap对象,避免内存的浪费。
内存缓存(LruCache ,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除,在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。)另外传入 LruCache 的键值对不能是 null。
Lrucache:LRU即Least Recently Used,近期最少使用算法。也就是当内存缓存达到设定的最大值时将内存缓存中近期最少使用的对象移除,有效的避免了OOM的出现。Lru算法的实现就是通过LinkedHashMap来实现的。LinkedHashMap继承于HashMap,它使用了一个双向链表来存储Map中的Entry顺序关系,这种顺序有两种,一种是LRU顺序,一种是插入顺序LruCache中将LinkedHashMap的顺序设置为LRU顺序来实现LRU缓存,每次调用get(也就是从内存缓存中取图片),则将该对象移到链表的尾端。调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。
补充:LruMemoryCache代码和v4包的LruCache一样,只是加了一个存储超期的处理
硬盘缓存(DiskLruCache,通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data/<application package>/cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。)
DiskLruCache移除缓存:remove()方法中要求传入一个key,然后会删除这个key对应的缓存图片。这个方法我们并不应该经常去调用它。因为你完全不需要担心缓存的数据过多从而占用SD卡太多空间的问题,DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。只有你确定某个key对应的缓存内容已经过期,需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。每当版本号改变,缓存路径下存储的所有数据都会被清除掉,因为DiskLruCache认为当应用程序有版本更新的时候,所有的数据都应该从网上重新获取
图片显示按需加载,图片大小进行缩放(设置inJustDecodeBounds参数和BitmapFactory.Options的采样率),图片像素进行处理(RGB_565会比使用ARGB_8888少消耗2倍的内存),图片回收(生成Bitmap对象的BitmapFactory的四类方法最终都是在安卓底层实现的,对应着BitmapFactory类的几个native方法,最终都是通过JNI调用方式实现的。所以,加载Bitmap到内存里以后,是包含两部分内存区域的:Bitmap对象存储在Dalvik heap中,而Bitmap对象的像素数据则存储在Native Memory(本地内存),由Java部分分配的,不用的时候系统就会自动回收了,但是那个对应的C可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。最初需要调用recycle()方法来释放C部分的内存,安卓3.0以后,Bitmap的像素数据和Bitmap对象一起存储在Dalvik heap中,系统会自动释放)
补充:BitmapFactory.Options.inBitmap的这个字段,假如这个字段被设置了,我们在解码Bitmap的时候,他会去重用inBitmap设置的Bitmap,减少内存的分配和释放,提高了应用的性能
7.避免内部调用get,set(字段搜寻比方法调用效率高)
8.减少APK大小
9.能用基本类型如Int,Long,就不用Integer,Long对象,基本类型变量占用的内存资源比相应对象占用的少得多
10.避免内存泄漏 Android内存泄露抓取工具leakcanary (leakcanry在application中配置,它通过弱引用方式侦查Activity或对象的生命周期,若发现内存泄露得到泄露的最短路径,最后通过notification展示。)
1.非静态内部类的静态实例容易造成内存泄漏
2.activity使用静态成员
3.使用handler时的内存问题(onDestroy时清除消息,mHandler.removeCallbacksAndMessages(null);)
4.注册某个对象后未反注册
5.集合中对象没清理造成的内存泄露
6.资源对象没关闭造成的内存泄露
7.构造Adapter时,没有使用缓存的 convertView
8.兜底回收 在Activity onDestory时候从view的rootview开始,递归释放所有子view涉及的图片,背景,DrawingCache,监听器等等资源,让Activity成为一个不占资源的空壳,泄露了也不会导致图片资源被持有。