安卓中的内存泄漏

因为安卓是基于java语言的,所以我们先来看一看java中的内存泄漏,然后在此基础上来谈谈安卓中的内存泄漏。

一java中的内存泄漏:

java中的内存泄漏主要是指在堆中分配的内存,明明已经不需要的时候,还仍然保留着访问它的引用,导致GC回收不能及时回收(关于GC回收不做过多赘述),导致这种情况出现的最主要原因是长生命周期的对象持有短生命周期对象的引用,导致短生命周期的对象明明已经不需要却无法被GC回收,从而导致内存泄漏。主要包括以下几种情况:

1在一个类中创建了一个非静态内部类的静态实例,如下所示:

public class Outer
{
    static Inner inner= null;  

   void doSomething()
   {
	//do something
   }
    class Inner
    {
      void doSomething()
      {
         System.out.println("dosth.");
      }
    }
}

在上述代码中,在第一次创建外部类Outer的实例时,会自动加载内部类inner(因为被static修饰),而内部类Inner持有外部类Outer的引用,且内部类inner的生命周期显然和整个程序的生命周期相同(被static修饰),这样当不需要使用外部类时,因为inner持有outer的引用,导致outer不能被GC回收,导致内存泄漏。

2使用java中的集合框架添加的对象在不需使用时未清除

如果我们把一些对象的引用加入到了集合中,当我们不需要该对象时,如果没有把它的引用从集合中清理掉,而仅仅是将其用用赋值为null,让GC去回收(而事实上GC是不会回收的),代码如下:

Vector v = new  Vector( 10 );  
for  ( int  i = 1 ;i < 100 ; i ++ ){  
Object o = new  Object();  
v.add(o);  
o = null ;  
}

如在上述代码中,我们在一个for循环中不断产生新的Object对象,然后将其添加到集合Vector中,然后将该对象的引用置为空(本意是置为null之后,让GC去回收),但事实上GC是不会去回收的,因为虽然Object对象的引用被置空,但是仍然存在其它的引用路径能够找到该对象,这个引用是从Vector集合对象中找到的,即尽管 o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此
Java 程序发生了内存泄漏。

要解决此种情况的泄漏,需要在对象不需要使用时调用remove()方法将该对象从集合中清除掉。

3不合理的使用单例模式

其实此种情况与第一种情况非常类似,都是因为static关键字导致的内存泄漏。代码如下:

//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    public static Singleton getInstance() {
         if (single == null) {
             single = new Singleton();
         }
        return single;
    }
}

可以看到单例模式的类都是被static修饰的,因此该类的实例的生命周期与整个程序的生命周期相同,因此很容易造成内存泄漏。

4数据库连接,网络连接(socket)和IO连接在不使用时未使用close()方法将连接关闭

这种情况只要注意在不需要使用资源时用close()方法将其关闭即可。

5修改hashset中对象的参数值,且参数是计算哈希值的字段:

这种情况与第二种情况非常类似,因为在第二种情况中我们已经讨论过在使用java集合框架时避免内存泄漏的关键是当对象不需使用时将其从集合中remove掉。

但当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段,否则对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中删除当前对象,造成内存泄露。

二安卓中的内存泄漏:

因为安卓是基于java语言的,所以很多情况与上述讲述的java内存泄漏是相同的。

1)注意Activity的泄漏

通常来说,Activity的泄漏是内存泄漏里面最严重的问题,它占用的内存多,影响面广,我们需要特别注意以下两种情况导致的Activity泄漏:

内部类引用导致Activity的泄漏

最典型的场景是Handler导致的Activity泄漏,如果Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏。此时的引用关系链是Looper -> MessageQueue -> Message -> Handler -> Activity。为了解决这个问题,可以在UI退出之前,执行remove Handler消息队列中的消息与runnable对象。或者是使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的。

Activity Context被传递到其他实例中,这可能导致自身被引用而发生泄漏。

内部类引起的泄漏不仅仅会发生在Activity上,其他任何内部类出现的地方,都需要特别留意!我们可以考虑尽量使用static类型的内部类,同时使用WeakReference的机制来避免因为互相引用而出现的泄露。

2)考虑使用Application Context而不是Activity Context

对于大部分非必须使用Activity Context的情况(Dialog的Context就必须是Activity Context),我们都可以考虑使用Application Context而不是Activity的Context,这样可以避免不经意的Activity泄露。

3)构造Adapter时,没有使用缓存的convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法:

public View getView(int position, ViewconvertView, 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对象的话,会白白浪费内存资源,会使得内存占用越来越大。

4)注意监听器的注销

在Android程序里面存在很多需要register与unregister的监听器,我们需要确保在合适的时候及时unregister那些监听器。自己手动add的listener,需要记得及时remove这个listener。

5).资源对象没关闭造成的内存泄漏

资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。

因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null.在我们的程序退出时一定要确保我们的资源性对象已经关闭。

以下是错误代码及正确代码的示范:

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 
 
} 
 
} 
 
}

Bitmap对象不在使用时调用recycle()释放内存

虽然在大多数情况下,我们会对Bitmap增加缓存机制,但是在某些时候,部分Bitmap是需要及时回收的。例如临时创建的某个相对比较大的bitmap对象,在经过变换得到新的bitmap对象之后,应该调用Bitmap.recycle()方法尽快回收原始的bitmap,这样能够更快释放原始bitmap所占用的空间。

需要特别留意的是Bitmap类里面提供的createBitmap()方法,如图所示:

这个函数返回的bitmap有可能和source bitmap是同一个,在回收的时候,需要特别检查source bitmap与return bitmap的引用是否相同,只有在不等的情况下,才能够执行source bitmap的recycle方法。

好了以上就是本人理解的关于安卓中内存泄漏的知识,另外推荐大家看一下:http://www.jb51.net/article/77899.htm,用代码的形式详细介绍了几种内存泄漏与解决方案。如果大家觉得不错记得顶一下哦。

时间: 2025-01-31 06:46:03

安卓中的内存泄漏的相关文章

Java中的内存泄漏

[转]介绍Java中的内存泄漏 1. 什么是内存泄漏? 内存泄漏的定义:对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着. 要想理解这个定义,我们需要先了解一下对象在内存中的状态.下面的这张图就解释了什么是无用对象以及什么是未被引用对象. 2. 为什么会发生内存泄漏? 来先看看下面的例子,为什么会发生内存泄漏.下面这个例子中,A对象引用B对象,A对象的生命周期(t1-t4)比B对象的生命周期(t2-t3)长的多.当B对象没有被应用程序使用之后,A对象仍然在引用着B对象.

JavaScript 中的内存泄漏

JavaScript 是一种垃圾收集式语言,这就是说,内存是根据对象的创建分配给该对象的,并会在没有对该对象的引用时由浏览器收回.JavaScript 的垃圾收集机制本身并没有问题,但浏览器在为 DOM 对象分配和恢复内存的方式上却有些出入. Internet Explorer 和 Mozilla Firefox 均使用引用计数来为 DOM 对象处理内存.在引用计数系统,每个所引用的对象都会保留一个计数,以获悉有多少对象正在引用它.如果计数为零,该对象就会被销毁,其占用的内存也会返回 给堆.虽然

在 JNI 编程中避免内存泄漏

JAVA 中的内存泄漏 JAVA 编程中的内存泄漏,从泄漏的内存位置角度可以分为两种:JVM 中 Java Heap 的内存泄漏:JVM 内存中 native memory 的内存泄漏. Java Heap 的内存泄漏 Java 对象存储在 JVM 进程空间中的 Java Heap 中,Java Heap 可以在 JVM 运行过程中动态变化.如果 Java 对象越来越多,占据 Java Heap 的空间也越来越大,JVM 会在运行时扩充 Java Heap 的容量.如果 Java Heap 容量

了解 JavaScript 应用程序中的内存泄漏

简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许多功能无需考虑内存管理即可实现,但却忽略了它可能在程序中带来重大的问题.不当清理的对象可能会存在比预期要长得多的时间.这些对象继续响应事件和消耗资源.它们可强制浏览器从一个虚拟磁盘驱动器分配内存页,这显著影响了计算机的速度(在极端的情形中,会导致浏览器崩溃). 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在.在最近几

Java中的内存泄漏问题

今天来谈谈Java语言中的内存泄漏问题,可能还有人不知道什么是内存泄漏,先来说下内存泄漏的概念. 内存泄漏:比较正式的说法是,不再使用的对象,却不能被Java垃圾回收机回收.用我的话来说,就是Java垃圾回收不能回收的空间. 产生的条件:从概念可以看出来产生内存泄漏必须满足两个必要条件: 一是对象还存在引用,但是在以后的程序中不会再被使用 二是这些对象不能被垃圾回收掉(原因是对象还有引用). 解决办法:这就需要我们在编程时保持好的编程习惯, 1.对于不再使用的对象,需要及时为他赋值为null 2

Java中关于内存泄漏出现的原因以及如何避免内存泄漏(超详细版)

Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题.内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收.最近自己阅读了大量相关的文档资料,打算做个 总结 沉淀下来跟大家一起分享和学习,也给自己一个警示,以后 coding 时怎么避免这些情况,提高应用的体验和质量. 我会从 java 内存泄漏的基础知识开始,并通过具体例子来说明 Android 引起内存泄漏的各种原因,以

VS中检测内存泄漏的方法

vs中检测内存泄漏的方法 分类: MFC2013-03-08 21:44 2764人阅读 评论(0) 收藏 举报 使用vs的内存检测有以下几种方法. 在debug模式下以F5运行: 方法一: [html] view plaincopy #define CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> //在入口函数中包含 _CrtDumpMemoryLeaks(); //即可检测到内存泄露 //以如下测试函数为例: i

JavaScript中的内存泄漏以及如何处理

随着现在的编程语言功能越来越成熟.复杂,内存管理也容易被大家忽略.本文将会讨论JavaScript中的内存泄漏以及如何处理,方便大家在使用JavaScript编码时,更好的应对内存泄漏带来的问题. 概述 像C语言这样的编程语言,具有简单的内存管理功能函数,例如malloc( )和free( ).开发人员可以使用这些功能函数来显式地分配和释放系统的内存. 当创建对象和字符串等时,JavaScript就会分配内存,并在不再使用时自动释放内存,这种机制被称为垃圾收集.这种释放资源看似是"自动"

闭包中的 内存泄漏

内存泄漏 如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁. 1 function assignHandler(){ 2 var element = document.getElementById("someElement"); 3 element.onclick = function(){ 4 alert(element.id); 5 } 6 } 而这个闭包则又创建另一个循环引用.由于匿名函数保存了一个对 assignHandler()的活动对象的引用,因此