为了是垃圾回收器正常释放程序所占用的内存,应该尽量避免内存泄露的情况(通常是全局成员变量持有对象引用导致的)。
例如一个activity中包含整个应用的Context (getApplicationContext)对象,因为该context的生命周期通常比该activity长,所以导致该activity直到应用退出才能被回收。
1. 节制地使用service
除非必要(如守护进程)只有当需要使用service时,才让其运行,在任务执行完后,及时的停止service。因为系统倾向于将service依赖的进程进行保留,如果让service一直处于后台,会非常消耗内存。
为了能够有效的控制service的生命周期,Android官方推荐使用IntentService,这种service的特点是在任务结束后会自动停止,从而避免了service内存泄露的可能性。
2. 当应用的activity都不可见时释放内存
Activity的onStop方法是当前activity不可见时被调用,我们可以在onStop中释放掉一些activity相关的资源,如取消网络连接,注销广播接收器等,但是UI相关的资源一直要等到onTrimMemory(TRIM_MEMORY_UI_HIDDEN)这个回调执行才被释放。这样做的目的是为了从应用程序的一个activity切换回另外一个activity时,界面相关资源不需要重新加载,提高相应速度。
我们可以在系统内存紧张时释放内存,通过重写onTrimMemory()方法,其回调类型有如下几种:
1) TRIM_MEMORY_UI_HIDDEN, 应用所有UI都不可见时调用,可以在此释放所有UI资源。
2) …
3. 避免在bitmap上浪费内存
1)高效加载大图
根据情况显示合适分辨率的图片,因为一张bitmap对象所占用的内存不是图片在硬盘中占用的大小,而是按像素来计算的。如一张100K的图片,像素是1500*1000,使用ARGB_8888,每个像素占4字节,那么加载该图片占用的内存是1500*1000*4字节。
如何加载图片呢?
BitmapFactory这个类提供了很多解析方法(decodeByteArray, decodeFile, decodeResource等)来创建Bitmap对象。我们可根据图片的来源选择合适的方法。如SD卡中的图片可以使用decodeFile,网络上的图片可以使用decodeStream方法,资源文件夹中的图片可以使用decodeResource方法。这些方法会为已构建的Bitmap分配内存。此时很容易出现OOM.
由于为每一种解析方法都提供了BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设为true,就可以禁止解析方法为bitmap分配内存,于是该解析方法返回的将不是bitmap对象,而是null。虽然返回的bitmap为null,但是BitmapFactory.Options的outWidth, outHeight, outMimeType属性都会被赋值。从而我们可以根据这些属性对图片进行压缩。
为了避免OOM,加载图片时应先检查其大小。根据上面的方法得到图片大小,从而决定shi加载整张图片到内存还是加载压缩或裁减的图片到内存。比如ImageView只有128*96像素,只是为了显示一张缩略图,此时把一张1024*768的图片加载到内存显然是不合适的。
怎样压缩图片呢?
可以通过设置tmapFactory.Options的inSampleSize值来实现。如2048*1536像素的图片,在inSampleSize为4时,图片将压缩为512*384。
2)使用图片缓存技术
在应用程序UI界面显示一张图片是比较简单的事情,但是当需要在界面上加载一大堆图片时,情况就比较复杂。比如使用ListView,GridView,ViewPager在屏幕上显示图片,并且可以滑动屏幕更新图片时,很容易OOM。
一般情况下,如果我们直接将不再显示的图片进行GC操作,OOM情况可能会避免,但是考虑到如果图片被回收后,用户由滑到该图片处,又得重新加载,比较耗时,严重影响响应速度与流畅性。
内存缓存技术对那些占用大量内存的图片提供了快速访问的方法。其核心类是LruCache,它的算法原理就是把最近使用的图片对象用强引用存储在LinkedHashMap中,在该Map中的对象缓存值达到最大时,将最近不常使用的对象从内存中移除。
例如一个activity中包含整个应用的Context (getApplicationContext)对象,因为该context的生命周期通常比该activity长,所以导致该activity直到应用退出才能被回收。
1. 节制地使用service
除非必要(如守护进程)只有当需要使用service时,才让其运行,在任务执行完后,及时的停止service。因为系统倾向于将service依赖的进程进行保留,如果让service一直处于后台,会非常消耗内存。
为了能够有效的控制service的生命周期,Android官方推荐使用IntentService,这种service的特点是在任务结束后会自动停止,从而避免了service内存泄露的可能性。
2. 当应用的activity都不可见时释放内存
Activity的onStop方法是当前activity不可见时被调用,我们可以在onStop中释放掉一些activity相关的资源,如取消网络连接,注销广播接收器等,但是UI相关的资源一直要等到onTrimMemory(TRIM_MEMORY_UI_HIDDEN)这个回调执行才被释放。这样做的目的是为了从应用程序的一个activity切换回另外一个activity时,界面相关资源不需要重新加载,提高相应速度。
我们可以在系统内存紧张时释放内存,通过重写onTrimMemory()方法,其回调类型有如下几种:
1) TRIM_MEMORY_UI_HIDDEN, 应用所有UI都不可见时调用,可以在此释放所有UI资源。
2) …
3. 避免在bitmap上浪费内存
1)高效加载大图
根据情况显示合适分辨率的图片,因为一张bitmap对象所占用的内存不是图片在硬盘中占用的大小,而是按像素来计算的。如一张100K的图片,像素是1500*1000,使用ARGB_8888,每个像素占4字节,那么加载该图片占用的内存是1500*1000*4字节。
如何加载图片呢?
BitmapFactory这个类提供了很多解析方法(decodeByteArray, decodeFile, decodeResource等)来创建Bitmap对象。我们可根据图片的来源选择合适的方法。如SD卡中的图片可以使用decodeFile,网络上的图片可以使用decodeStream方法,资源文件夹中的图片可以使用decodeResource方法。这些方法会为已构建的Bitmap分配内存。此时很容易出现OOM.
由于为每一种解析方法都提供了BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设为true,就可以禁止解析方法为bitmap分配内存,于是该解析方法返回的将不是bitmap对象,而是null。虽然返回的bitmap为null,但是BitmapFactory.Options的outWidth, outHeight, outMimeType属性都会被赋值。从而我们可以根据这些属性对图片进行压缩。
为了避免OOM,加载图片时应先检查其大小。根据上面的方法得到图片大小,从而决定shi加载整张图片到内存还是加载压缩或裁减的图片到内存。比如ImageView只有128*96像素,只是为了显示一张缩略图,此时把一张1024*768的图片加载到内存显然是不合适的。
怎样压缩图片呢?
可以通过设置tmapFactory.Options的inSampleSize值来实现。如2048*1536像素的图片,在inSampleSize为4时,图片将压缩为512*384。
2)使用图片缓存技术
在应用程序UI界面显示一张图片是比较简单的事情,但是当需要在界面上加载一大堆图片时,情况就比较复杂。比如使用ListView,GridView,ViewPager在屏幕上显示图片,并且可以滑动屏幕更新图片时,很容易OOM。
一般情况下,如果我们直接将不再显示的图片进行GC操作,OOM情况可能会避免,但是考虑到如果图片被回收后,用户由滑到该图片处,又得重新加载,比较耗时,严重影响响应速度与流畅性。
内存缓存技术对那些占用大量内存的图片提供了快速访问的方法。其核心类是LruCache,它的算法原理就是把最近使用的图片对象用强引用存储在LinkedHashMap中,在该Map中的对象缓存值达到最大时,将最近不常使用的对象从内存中移除。