内存溢出(OOM)and内存泄露---及其解决

那么问题来了


什么是内存溢出out of memory?(OOM)

已有数据超出其分配内存所能存储的范围
比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。


什么是内存泄露memory leak?

 指程序在申请内存后,无法释放已申请的内存空间,


他们到底啥关系?

一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!


哪些情况经常导致内存溢出??如何解决呢??

  1. 当项目中包含大量图片,或者图片过大

      方法1:等比例缩小图片

      复制内容到剪贴板

      代码:

 BitmapFactory.Options options = new BitmapFactory.Options();

  options.inSampleSize = 4

  方法2:对图片采用软引用,及时地进行recyle()操作

  复制内容到剪贴板

  代码:

 SoftReference bitmap;

  bitmap = new SoftReference(pBitmap);

  if(bitmap != null){

  if(bitmap.get() != null && !bitmap.get().isRecycled()){

  bitmap.get().recycle();

  bitmap = null;

  }

  }

  方法3 : 对复杂的listview进行合理设计与编码1. 注意重用Adapter里面的convertView,以及holder机制的运用

  上述方法尝试还未成功,可用 lazy loading data

  复制内容到剪贴板

  代码:

public View getView(int position, View convertView, ViewGroup parent) {

  if (convertView == null) {

  v = mInflater.inflate(resource, parent, false);

  final int[] to = mTo;

  final int count = to.length;

  final View[] holder = new View[count];

  for (int i = 0; i < count; i++) {

  holder[i] = v.findViewById(to[i]);

  }

  v.setTag(holder); } else {

  }

  }

  方法4 : 单个页面,横竖屏切换N次后 OOM

  1. 看看页面布局当中有没有大的图片,比如背景图之类的。去除xml中相关设置,改在程序中设置背景图(放在onCreate()方法中):

  复制内容到剪贴板

  代码:

 Drawable bg = getResources().getDrawable(R.drawable.bg);

  XXX.setBackgroundDrawable(rlAdDetailone_bg);

  在Activity destory时注意,bg.setCallback(null); 防止Activity得不到及时的释放。

  2. 跟上面方法相似,直接把xml配置文件加载成view 再放到一个容器里,然后直接调用 this.setContentView(View view);避免xml的重复加载。

  方法5:在页面切换时尽可能少地重复使用一些代码。比如:重复调用数据库,反复使用某些对象等等…..

  方法6:Android堆内存也可以自己定义大小和优化Dalvik虚拟机的内存

  复制内容到剪贴板

  代码:

 private final static int CWJ_HEAP_SIZE= 6*1024*1024;

  private final static float TARGET_HEAP_UTILIZATION = 0.75f;

  VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);

  VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

内存泄露

常见的容易引起内存泄漏的代码
(一) 查询数据库没有关闭游标
(二) 构造Adapter时,没有使用缓存的 convertView
(三) Bitmap对象不在使用时调用recycle()释放内存
(四) 释放对象的引用
(五) 其他
正因为我们的应用程序能够使用的内存有限,所以在编写代码的时候需要特别注意内存使用问题。如下是一些常见的内存使用不当的情况。
(一) 查询数据库没有关闭游标
描述:
程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。
示例代码:
Cursor cursor = getContentResolver().query(uri …);
if (cursor.moveToNext()) {
… …
}
修正示例代码:
Cursor cursor = null;
try {
cursor = getContentResolver().query(uri …);
if (cursor != null && cursor.moveToNext()) {
… …
}
} finally {
if (cursor != null) {
try {
cursor.close();
} catch (Exception e) {
//ignore this
}
}
}
(二) 构造Adapter时,没有使用缓存的 convertView
描述:
以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:
public View getView(int position, View convertView, ViewGroup parent)
来 向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对象的过程可以查看:
android.widget.AbsListView.java –> void addScrapView(View scrap) 方法。
示例代码:
public View getView(int position, View convertView, ViewGroup parent) {
View view = new Xxx(…);
… …
return view;
}
修正示例代码:
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
populate(view, getItem(position));

} else {
view = new Xxx(…);

}
return view;
}
(三) Bitmap对象不在使用时调用recycle()释放内存
描述:
有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。可以看一下代码中的注释:
/**
* Free up the memory associated with this bitmap’s pixels, and mark the
* bitmap as “dead”, meaning it will throw an exception if getPixels() or
* setPixels() is called, and will draw nothing. This operation cannot be
* reversed, so it should only be called if you are sure there are no
* further uses for the bitmap. This is an advanced call, and normally need
* not be called, since the normal GC process will free up this memory when
* there are no more references to this bitmap.
*/
(四) 释放对象的引用
描述:
这种情况描述起来比较麻烦,举两个例子进行说明。
示例A:
假设有如下操作
public class DemoActivity extends Activity {
… …
private Handler mHandler = …
private Object obj;
public void operation() {
obj = initObj();

[Mark]
mHandler.post(new Runnable() {
public void run() {
useObj(obj);
}
});
}
}
我们有一个成员变量 obj,在operation()中我们希望能够将处理obj实例的操作post到某个线程的MessageQueue中。在以上的代码中,即便是 mHandler所在的线程使用完了obj所引用的对象,但这个对象仍然不会被垃圾回收掉,因为DemoActivity.obj还保有这个对象的引用。 所以如果在DemoActivity中不再使用这个对象了,可以在[Mark]的位置释放对象的引用,而代码可以修改为:
… …
public void operation() {
obj = initObj();

final Object o = obj;
obj = null;
mHandler.post(new Runnable() {
public void run() {
useObj(o);
}
}
}
… …
示例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生命周期的介绍,以 明确何时应该释放哪些资源。

文章参考以下网上资料,总结整理,非常感谢,特此贴出

http://android.chinatarena.com/jsfx/1571.html#6d

http://blog.csdn.net/com360/article/details/6682409

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值