- 浏览: 516624 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
tangyunliang:
大哥你太历害了谢谢
Android基于XMPP Smack Openfire开发IM【四】初步实现两个客户端通信 -
u013015029:
LZ,请问下,在// 添加消息到聊天窗口 , 这里获取Ed ...
Android基于XMPP Smack Openfire开发IM【四】初步实现两个客户端通信 -
endual:
怎么保持会话,我搞不懂啊
Android基于XMPP Smack Openfire开发IM【一】登录openfire服务器 -
donala_zq:
显示:[2013-11-30 11:50:36 - Andro ...
android-----------新浪微博 -
donala_zq:
哥,运行不了啊
android-----------新浪微博
一、 Android的内存机制
Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似。程序员通过new为对象分配内存,所有对象在java堆内分配空间;然而对象的释放是由垃圾回收器来完成的。
那么GC怎么能够确认某一个对象是不是已经被废弃了呢?Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象可以作为有向图的起始顶点,该图就是从起始顶点开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。
二、Android的内存溢出
Android的内存溢出是如何发生的?
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。
为什么会出现内存不够用的情况呢?我想原因主要有两个:
由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。
保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。
三、常见的内存泄漏
1.万恶的static
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了。
以上的代码是很危险的,如果将Activity赋值到么mContext的话。那么即使该Activity已经onDestroy,但是由于仍有对象保存它的引用,因此该Activity依然不会被释放.
如何才能有效的避免这种引用的发生呢?
第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
第二、Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
第三、使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;
2.线程惹的祸
线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。
这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横 屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。
由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。
这种线程导致的内存泄露问题应该如何解决呢?
第一、将线程的内部类,改为静态内部类。
第二、在线程内部采用弱引用保存Context引用。
另外,我们都知道Hanlder是线程与Activity通信的桥梁,我们在开发好多应用中会用到线程,有些人处理不当,会导致当程序结束时,线程并没有被销毁,而是一直在后台运行着,当我们重新启动应用时,又会重新启动一个线程,周而复始,你启动应用次数越多,开启的线程数就越多,你的机器就会变得越慢。
所以我们在应用退出时,要将线程销毁,我们只要在Activity中的,onDestory()方法处理一下就OK了,如下代码所示:
3.超级大胖子Bitmap
可以说出现OutOfMemory问题的绝大多数人,都是因为Bitmap的问题。因为Bitmap占用的内存实在是太多了,它是一个“超级大胖子”,特别是分辨率大的图片,如果要显示多张那问题就更显著了。
如何解决Bitmap带给我们的内存问题?
第一、及时的销毁。
虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要 及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。
第二、设置一定的采样率。
有时候,我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。
4.行踪诡异的Cursor
Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。
然而如果Cursor的数据量特表大,特别是如果里面有Blob信息时,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编程者手动的将Cursor close掉
5.构造Adapter时,没有使用缓存的 convertView
描述:
以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:
来 向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对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。
Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似。程序员通过new为对象分配内存,所有对象在java堆内分配空间;然而对象的释放是由垃圾回收器来完成的。
那么GC怎么能够确认某一个对象是不是已经被废弃了呢?Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象可以作为有向图的起始顶点,该图就是从起始顶点开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。
二、Android的内存溢出
Android的内存溢出是如何发生的?
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。
为什么会出现内存不够用的情况呢?我想原因主要有两个:
由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。
保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。
三、常见的内存泄漏
1.万恶的static
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了。
public class ClassName { private static Context mContext; //省略 }
以上的代码是很危险的,如果将Activity赋值到么mContext的话。那么即使该Activity已经onDestroy,但是由于仍有对象保存它的引用,因此该Activity依然不会被释放.
如何才能有效的避免这种引用的发生呢?
第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
第二、Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
第三、使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;
2.线程惹的祸
线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new MyThread().start(); } private class MyThread extends Thread{ @Override public void run() { super.run(); //do somthing } } }
这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横 屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。
由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。
这种线程导致的内存泄露问题应该如何解决呢?
第一、将线程的内部类,改为静态内部类。
第二、在线程内部采用弱引用保存Context引用。
另外,我们都知道Hanlder是线程与Activity通信的桥梁,我们在开发好多应用中会用到线程,有些人处理不当,会导致当程序结束时,线程并没有被销毁,而是一直在后台运行着,当我们重新启动应用时,又会重新启动一个线程,周而复始,你启动应用次数越多,开启的线程数就越多,你的机器就会变得越慢。
package com.tutor.thread; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; public class ThreadDemo extends Activity { private static final String TAG = "ThreadDemo"; private int count = 0; private Handler mHandler = new Handler(); private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,我们用Log打印出来 Log.e(TAG, Thread.currentThread().getName() + " " +count); count++; setTitle("" +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过Handler启动线程 mHandler.post(mRunnable); } }
所以我们在应用退出时,要将线程销毁,我们只要在Activity中的,onDestory()方法处理一下就OK了,如下代码所示:
@Override protected void onDestroy() { mHandler.removeCallbacks(mRunnable); super.onDestroy(); }
3.超级大胖子Bitmap
可以说出现OutOfMemory问题的绝大多数人,都是因为Bitmap的问题。因为Bitmap占用的内存实在是太多了,它是一个“超级大胖子”,特别是分辨率大的图片,如果要显示多张那问题就更显著了。
如何解决Bitmap带给我们的内存问题?
第一、及时的销毁。
虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要 及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。
第二、设置一定的采样率。
有时候,我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。
4.行踪诡异的Cursor
Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。
然而如果Cursor的数据量特表大,特别是如果里面有Blob信息时,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编程者手动的将Cursor close掉
5.构造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对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。
发表评论
-
Android中如何模拟一次点击(touch)事件
2014-05-06 10:41 0在Android中有时需要模拟某一个View的touch事件, ... -
Android程序Crash时的异常上报
2014-04-28 18:15 0http://blog.csdn.net/singwhatiw ... -
android程序中证书签名校验的方法
2014-04-28 17:58 1898android程序中证书签名校验的方法一 2013-02 ... -
MD5理解错了,哎
2014-03-17 14:14 0MD5只对数据加密是无法解密的,也就是说,你把100加密后,就 ... -
Android 获取网络时间
2014-03-12 11:42 2006Android 获取网络时间 在网上看到的最常见的方式有: ... -
SQLite清空表并将自增列归零
2014-03-05 18:02 1461SQLite清空表并将自增列归零 作者:Zhu Yanfeng ... -
Handler小看一下
2013-11-11 16:42 0android handler调用post方法还是阻塞 su ... -
Frame Animation小看一下
2013-10-12 16:30 713Demo运行效果图: 源码: -
动画小学一下
2013-10-12 16:14 689转自: http://www.eoeandroid.com/f ... -
Android 动画之ScaleAnimation应用详解
2013-10-12 15:49 955===============eoeAndroid社区推荐:= ... -
android开发中的一个工具类
2013-06-19 16:04 0package com.wanpu.login.dialog; ... -
android TextView怎么设置个别字体颜色并换行?
2013-06-20 09:25 1629(1)、TextView 设置个别字体颜色 TextView ... -
Android开发之文件下载,状态时显示下载进度,点击自动安装
2013-05-07 15:38 1361在进行软件升级时,需要进行文件下载,在这里实现自定义的文件下载 ... -
android中的状态保存
2013-04-07 14:21 931package com.zzl.call; import ... -
android动画基础:tween动画
2013-04-06 11:21 1179工程结构图: [img] [/img] 四个动画的xml ... -
面试中遇到的几个问题
2013-06-09 11:56 938SAX与DOM之间的区别 SAX ( ... -
Android获取其他包的Context实例,然后调用它的方法,反射!!!
2013-03-25 10:32 1156Android中有Context的概念,想必大家都知道。Con ... -
JUnit测试小小demo
2013-03-06 16:37 1080运行效果图: [img] [/img] 项目结构图 ... -
android开发中的异常小工具
2013-03-04 15:53 860package com.zzl.tools; impor ... -
仿大众点评源码(部分)
2013-06-09 11:54 1827项目中的一些界面: [img] [/img] [img] ...
相关推荐
关于android内存机制的介绍,以及bitmap的内存泄露等问题的处理方式
Android内存优化——常见内存泄露及优化方案 Android内存优化——常见内存泄露及优化方案
Android处理内存泄漏的代码例子。用于演示避免内存泄漏的几种方法,包括:关闭游标、重用适配、回收图像、注销监听、释放引用。
Android webview 内存泄露的解决方法 最近在activity嵌套webview显示大量图文发现APP内存一直在涨,没法释放内存,查了很多资料,大概是webview的一个BUG,引用了activity导致内存泄漏,所以就尝试传递...
Android内存优化——常见内存泄露及优化方案
Android内存泄漏简介 不少人认为java程序,因为有垃圾回收机制,应该没有内存泄漏 1.引用没有释放造成的内存泄漏 2.资源对象没有关闭造成的内存泄漏 3.一些不良代码造成的内存压力 4.JNI代码的内存泄漏
Android内存优化——常见内存泄露及优化方案 对于安卓优化见解独到,一针见血,从此再无此问题
主要处理一些有关Android内存泄露案例以及解决方案,比如我们常见的单例模式、listView的的优化
Android 内存泄露 Mat工具分析。非常好的分析工具讲解
Android 内存 OOM 优化和治理,Android 内存泄漏原因详解与应对措施,Android 中的 Bitmap 使用详解,Android 中的 Bitmap 内存治理和优化详解,Android 内存分析命令详解,Java内存模型。Android 内存 OOM 优化和...
Android 内存泄露原因分析。通过原因分析,再接合代码可查明具体原因,发现对策
主要介绍了Android Native 内存泄漏系统化解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
android 内存泄露测试.
android系统分析内存泄露测试android系统分析内存泄露测试android系统分析内存泄露测试
android检查内存泄露和用法 <!--==============================================================================--> android:name="com.squareup.leakcanary.internal.HeapAnalyzerService" android:enabled...
android 的内存溢出和泄露问题. 内存溢出就是分配的内存不足以放下数据项序列。如在一个域中输入的数据超过了它的要求就会引发数据溢出问题,多余的数据就可以作为指令在计算机上运行。 内存泄漏是指在堆上分配...
本篇文章主要介绍了用Android Studio检测内存泄露的问题的解决方法,Android Studio在为我们提供了良好的编码体验的同时,也提供了许多对App性能分析的工具,下面我们一起来了解一下。
android内存泄露的检测和排查,已经附带一个锁屏内存泄露的例子分析。
Android 内存溢出和内存泄漏的问题 在面试中,经常有面试官会问“你知道什么是内存溢出?什么是内存泄漏?怎么避免?”通过这篇文章,你可以回答出来了。 内存溢出 (OOM)是指程序在申请内存时,没有足够的内存空间...
帧动画太多造成内存泄漏问题,内含所需的JAR包:org.apache.commons.io.IOUtils,将Inputstream转为byte字节数组,减少内存泄漏 和关键代码,仅供参考,如有建议请在下方留言或添加咨询~~~