内存溢出(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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-11 07:40:29

内存溢出(OOM)and内存泄露---及其解决的相关文章

内存溢出(Oom)和内存泄露(Memory leak)

内存溢出(Oom):运行内存大于可用内存的情况.比如申请了一个integer空间,结果存放下了只有long才能存放的数据 内存泄露(Memory leak):程序员忘记释放已用内存的情况,是内存管理较为常见的现象 以发生的方式来分类,内存泄漏可以分为4类: 1. 常发性内存泄漏.发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏. 2. 偶发性内存泄漏.发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生.常发性和偶发性是相对的.对于特定的环境,偶发性的也许就变成了常发性

转:Tomcat内存溢出的三种情况及解决办法分析

Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种情况: 1.OutOfMemoryError: Java heap space 2.OutOfMemoryError: PermGen space 3.OutOfMemoryError: unable to create new native thread. Tomcat内存溢出解决方案 对于前两种

Tomcat内存溢出的三种情况及解决办法分析

转自 http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380147d8c8c4668d4e419ce3b4c413037bfa6663f405a8e906b6075aa1f0ce9f03176370123b5989b8908dcac925f75ce786a6459db0144dc4ee59a1167877bcd06feaf68bce6e732e2e88893880705dd53742bddaccd095b4

Java中OutOfMemoryError(内存溢出)的三种情况及解决办法

相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各类问题经验的积累以及对问题根源的探索,终于有了一个比较深入的认识. 在解决java内存溢出问题之前,需要对jvm(java虚拟机)的内存管理有一定的认识.jvm管理的内存大致包括三种不同类型的内存区域:Permanent Generation space(永久保存区域).Heap space(堆区域).Java Stacks(Java栈).其中永久保存区域主要存放Class

(转)Java中OutOfMemoryError(内存溢出)的三种情况及解决办法

面试时面试关问了有关内存溢出的出现情况和解决方法,网上百度了下,在此感谢 作者liqianbnu总结. 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各类问题经验的积累以及对问题根源的探索,终于有了一个比较深入的认识.在解决java内存溢出问题之前,需要对jvm(java虚拟机)的内存管理有一定的认识.jvm管理的内存大致包括三种不同类型的内存区域:Permanent Generation space(永久保存区域).H

【转】Java内存溢出(java.lang.OutOfMemoryError)问题及其解决方法

Java内存溢出(java.lang.OutOfMemoryError)问题及其解决方法 内存溢出有两种情况,如下: 相关配置以Tomcat环境为例 一.java.lang.OutOfMemoryError: PermGen space PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的. Class在被Loader时就会被放到PermGen space中,它和存放类实例(Insta

bitmap 内存溢出OOM的解决办法分享

昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bitmap报的错.第一次调用都没问题,第二次再次调用就会报上面那个内存溢出的问题.而且有的手机报有的手机不报.研究了半天终于解决.首先分析了下原因,应该是图片占用的内存超过了系统虚拟机可分配的最大限制.不同手机可能分配的最大值不一样.后来找到解决办法主要是设置BitmapFactory.Options.

内存溢出OOM

1, OutOfMemoryError异常 除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能, javaHeap 溢出 一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常. 出现这种异常,一般手段是先通过内

java常见内存溢出(OOM)

jvm内存区域 程序计数器一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器. java栈与程序计数器一样,java栈(虚拟机栈)也是线程私有的,其生命周期与线程相同.通常存放基本数据类型,对象引用(一个指向对象起始地址的引用指针或一个代表对象的句柄),reeturnAddress类型(指向一条字节码指令的地址) 栈区域有两种异常类型:如果线程请求的栈深度大于虚拟机所允许的深度,将抛StrackOverflowError异常:如果虚拟机栈可以动态扩展(大部分虚拟机都可动态扩展),当扩展

内存溢出,与内存泄露

内存泄漏: memory leak :是指程序在申请内存后,无法释放已申请的内存空间 ; 只出不进漏气一样 内存溢出:就是你要的内存空间超过了系统实际分配的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误: 比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢.就是分配的内存不足以放下数据项序列,称为内存溢出.说白了就是我承受不了那么多,那我就报错 你是不是该减肥了 内存泄漏的分类: a.常发性内存泄漏 :发生内存泄漏的代码会被多次执行到,每次被执行