Android内存泄露的原因

(一)释放对象的引用,误将一个本来生命周期短的对象存放到一个生命周期相对较长的对象中,也称“对象游离“。隐蔽的内部类(Anonymous Inner Class):

mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

....

}

};

相当于:

class MyHandler implements Handler {

....

}

mHandler = new MyHandler();

类似的还有Listener,Observer,Receiver等。
    由于内部类隐含拥有一个外部类对象的引用,所以千万要注意内部类instance的声明周期。
    最好不要将一个内部类的instance暴漏出去,除非使用者采用weak reference引用内部类的instance。例如,一些Handler,Listener在做为返回值暴漏出去时,千万注意使用weak reference。
    注意:一些系统提供的类偷偷地将自己暴漏出去了,如FileObserver,会将自己暴漏到自己内部开的线程去,不过还好它使用的是weak reference。但是过分的是BroadcastReceiver,一旦我们使用Context的registerReceiver 之后,系统( ActivityManagerNative )就会有一个它的强引用,除非我们显式调用unregisterReceiver。

结论:任何提供了开关函数的类,都必须保证显式地调用它们的开关函数。

(二) 构造Adapter时,没有使用缓存的 convertView,从而造成系统创建了大量的view而没有来得及回收。

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

(三)对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null。资源性对象,比如(Cursor等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。

(四)都是线程惹的祸

由于线程的执行时间是未知的,所以线程所持有的外部对象,一般要使用weak reference,除非你肯定它们的生命周期。

另外,向其它线程post Runnable或者send Message时也需要注意Runnalbe内部使用的变量和Message中的内容。

(五)AsyncTask-隐藏的故事

Asynctask使用了一个静态的ThreadPoolExecutor,有三个参数是系统固定的:

CORE_POOL_SIZE:5

MAXIMUM_POOL_SIZE:128

QUEUE_CAPACITY: 10

当一个AsyncTask被execute之后:

1.如果线程池中线程数目小于CORE_POOL_SIZE ,就直接开线程;

2.如果队列不满,就被加入队列中;

3.如果队列已满,就直接开线程执行;

4.如果线程池中线程数目大于MAXIMUM_POOL_SIZE,就会Exception。

Tricky的地方在于AsncTask的Cancel操作。

1.不一定都能成功,例如while(true){}就无法被cancel;

2.如果AsyncTask还在Queue中,那么cancel操作并不会将它从Queue中remove,而仅仅是设置了flag,最终当它被thread执行时,判断该flag,如果false,就不会执行doBackground的代码。

悲剧剧情:你在队列中,正在执行的几个哥们都block了,你就一直呆着吧。

(六)Bitmap-不得不说的故事

Bitmaps in Android are created innative memory, not on the VM heap, so the actual Bitmap object on the VM heapis very small as it doesn‘t contain any actual bitmap data.

一般情况下,我们都是按需索图,没必要把原始图片都搞进来,所以我们可以先查询原始图片大小,在做scale:

1. 查询原始图片大小,通过BitmapFactory.Options中的属性inJustDecodeBounds来做,If set to true, the decoder will return null (nobitmap), but the out... fields will still be set, allowing the caller to querythe bitmap without having to llocate the memory for its pixels.

2. 然后计算出一个scale的值,通过BitmapFactory.Options中的属性inSampleSize进行缩放。

Bitmap bitmap;

float imagew = 300;  // 目标大小

float imageh = 300;  // 目标大小

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

bitmapFactoryOptions.inJustDecodeBounds = true;

bitmap = BitmapFactory.decodeFile(imageFile, bitmapFactoryOptions);

int yRatio = (int)Math.ceil(bitmapFactoryOptions.outHeight/imageh);

int xRatio = (int)Math.ceil(bitmapFactoryOptions.outWidth/imagew);

if (yRatio > 1 || xRatio > 1){

if (yRatio > xRatio) {

bitmapFactoryOptions.inSampleSize = yRatio;

} else {

bitmapFactoryOptions.inSampleSize = xRatio;

}

} else{

// inSampleSize = 1

}

bitmapFactoryOptions.inJustDecodeBounds = false;

bitmap = BitmapFactory.decodeFile(imageFile, bitmapFactoryOptions);

myImageView.setImageBitmap(bitmap);

    Bitmap-recycle有用吗?以下是官方源代码的注释:

Free the native object associated with this bitmap, and clearthe reference to the pixel data.

This will not free the pixel data synchronously;

it simply allows it to be garbagecollected if there are no other references. The bitmap is marked as "dead", meaning it willthrow an exception ifgetPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only becalled 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 processwill free up this memory when there are no more references to this bitmap.

(七)substring的恶梦

?    ?public String substring(int beginIndex, int endIndex) {

?    ?return new String(offset + beginIndex,

endIndex - beginIndex,

value);

?    ?}

?    ?String(int offset, int count, char value[]) {

?    ?    ? this.value = value;

?    ?    ? this.offset = offset;

?    ?    ? this.count = count;

?    ?}

?    ?也就是说即使你只想用其中的某几个字节,Java也自动把原始String的整个内容帮你保存下来了。

?    ?ArrayList<String> oomStringList = new ArrayList<String>(1024);

?    ?for (int i=0; i<32*1024; i++) {

?    ?String srcString = new String(new char[1024]);

?    ?String dstString = srcString.substring(0,1);

?    ?oomStringList .add(dstString);

?    ??}

refrence:http://blog.csdn.net/edisonlg/article/details/7082063

时间: 2024-10-13 10:02:15

Android内存泄露的原因的相关文章

Android内存泄露开篇

先来想这三个问题 内存泄露是怎么回事 内存会泄露的原因 避免内存泄露 1.内存泄露怎么回事 一个程序中,已经不需要使用某个对象,但是因为仍然有引用指向它垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露. Android的一个应用程序的内存泄露对别的应用程序影响不大. 为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进

android内存泄露调试,Heap,MAT

三.内存监测工具 DDMS --> Heap 无论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方.Android tools中的DDMS就带有一个很不错的内存监测工具Heap(这里我使用eclipse的ADT插件,并以真机为例,在模拟器中的情况类似).用Heap监测应用进程使用内存情况的步骤如下: 1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图.Heap视图都是打开的: 2. 将手机通过USB链接至电

深入Android内存泄露

深入内存泄露 Android应用的内存泄露,其实就是java虚拟机的堆内存泄漏. 1.知识储备 1.Java内存模型 相关内存对象模型,参照博客精讲Java内存模型 1) 寄存器(register).这是最快的保存区域,这是主要由于它位于处理器内部.然而,寄存器的数量十分有限,所以寄存器是需要由编译器分配的.我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹. (2) 堆栈(stack).在执行函数(方法)时,函数一些内部变量的存储都可以放在栈上面创建,函数执行结束的时候这

Android 内存泄露简介、典型情景及检测解决

什么是内存泄露? Android虚拟机的垃圾回收采用的是根搜索算法.GC会从根节点(GC Roots)开始对heap进行遍历.到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉.内存泄漏指的是进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到gc roots导致无法被GC回收.无用的对象占据着内存空间,导致不能及时回收这个对象所占用的内存.内存泄露积累超过Dalvik堆大小,就会发生OOM(OutOfMemory). 内存泄露的经典

Android内存泄露分析和处理

什么是内存泄露 Java使用有向图机制,通过GC自动检查内存中的对象,如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收. 内存泄露的原因 1.资源对象没关闭造成的内存泄漏 资源性对象比如 (Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存.它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外.如果我们仅仅是把它的引用设置为null

android 内存泄露调试

一.概述 1 二.Android(Java)中常见的容易引起内存泄漏的不良代码 1 (一) 查询数据库没有关闭游标 2 (二) 构造Adapter时,没有使用缓存的 convertView 3 (三) Bitmap对象不在使用时调用recycle()释放内存 4 (四) 释放对象的引用 4 (五) 其他 5 三.内存监测工具 DDMS --> Heap 5 四.内存分析工具 MAT(Memory Analyzer Tool) 7 (一) 生成.hprof文件 7 (二) 使用MAT导入.hpro

Android内存泄露总结

Android可能发生内存泄露的地方总结: 1.查询数据库没有关闭游标 2.构建adapter时,没有使用缓存的convertView 3.Bitmap对象不使用的时候调用recycle()方法释放内存 4.释放对象的引用 5.单例模式引用context,如果使用actvitiy-context,会造成内存泄露, 可以使用getApplicationContext()); 或getApplication()代替. 参考文档: A?n?d?r?o?i?d? ?内?存?泄?漏?调?试 http://

Android内存泄露案例分析

一款优秀的Android应用,不仅要有完善的功能,也要有良好的体验,而性能是影响体验的一个重要因素.内存泄露是Android开发中常见的性能问题.这篇文章,通过我们曾经遇到的一个真实的案例,来讲述一个内存泄露问题,从发现到分析定位,再到最终解决的全过程. 这里把整个过程分为四个阶段: 第一阶段,现场勘查,分析Bug现象,找出有用线索: 第二阶段,初步推断,根据之前的线索,推断可能导致Bug的原因,并且进一步验证推断是否正确: 第三阶段,探究根源,找出导致Bug的真正原因: 第四阶段,解决方案,研

Android 内存泄露测试数据处理--procrank,setprop,getprop(转)

1.Android内存测试常用的几个概念. VSS--virtual set size 虚拟耗用内存(包含共享库占用的内存)RSS--Resident set size实际使用的物理内存(包含共享库占用的内存)PSS--Proportional set size 实际使用的物理内存(比例分配共享库占用的内存)USS--Unique Set size:进程独自占用的物理内存(不包含共享库占用的内存)一般来说内存占用大小如下规律:VSS>=RSS>=Pss>=USS 2.Android pr