【转载】Android 内存溢出如何发生的。

且谈Android内存溢出

前言

关于android的内存溢出在创新文档库中也有不少,网络上也有很多这方面的资料.所以这遍文章不算是正真意义上的创新,仅仅只是对xxx源码中出现的一些android开发中容易犯错的代码习惯一次总结.

1.  Android的内存溢出是如何发生的

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M.因此我们所能利用的内存空间是有限的.如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误.

原因主要有两个: l  由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放. l  保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制.

2.  Static

static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例.所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多)就要谨慎对待了.例如xxx源码:

public class IntentMapping {      private static Contextcontext;      //. . .  }

如果将Activity赋值到么context的话.那么即使该Activity已经onDestroy,但是由于仍有对象保存它的引用,因此该Activity依然不会被释放.所以这里就潜在内存溢出.

再看android文档中的一个例子:

private static Drawable sBackground;

@Override      protected void onCreate(Bundle state){

     super.onCreate(state);

    TextView label = new TextView(this);

    label.setText(“Leaks are bad”);

     if(sBackground == null){

      sBackground = getDrawable(R.drawable.large_bitmap);

     }

     label.setBackgroundDrawable(sBackground);

      setContentView(label);

}

sBackground,是一个静态的变量,我们并没有显式的保存Contex的引用,但是,当Drawable与View连接之后,Drawable就将View设置为一个回调,由于View中是包含Context的引用的,所以,实际上我们依然保存了Context的引用.这个引用链如下:

Drawable->TextView->Context

所以,最终该Context也没有得到释放,发生了内存泄露,该部分的详细内容也可以参考Android文档中Article部分.

有效的避免内存溢出的方法:

1.应该尽量避免static成员变量引用资源耗费过多的实例,比如Context.

2.Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题.

3.使用WeakReference代替强引用.比如可以使用WeakReference<Context> mContextRef;

在这里要提到,在xxx中其实是有在ApplicationInit中将baseContext缓存下来,但可惜的是并没有很好的利用,而是在各自的模块中又缓存了自身的Context例如上面例子中的IntentMapping.

3.  线程

程产生内存泄露的主要原因在于线程生命周期的不可控.看看下面这段代码.

public class Pandareader extends BaseActivity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

`   new Thread() {             public void run() {

InitDataBase.initDB(Pandareader.this.getBaseContext());

//. . .

}

}

}

这段代码很平常也很简单,也是我们经常使用的形式.但存在一个问题:假设Thread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,这时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此.

由于我们的线程是Activity的内部类,所以Thread中保存了Activity的一个引用,当Thread的run函数没有结束时,Thread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此潜在内存泄露.

Android提供的AsyncTask同样也会潜在内存溢出的风险.因为Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露.

要避免线程的内存溢出要到2点:

1.  将线程的内部类,改为静态内部类.

2.  在线程内部采用弱引用保存Context引用.

4.  Bitmap

可以说出现OutOfMemory问题的绝大多数人,都是因为Bitmap的问题.因为Bitmap占用的内存实在是太多了,特别是分辨率大的图片,如果要显示或创建多张那OutOfMemory问题就更显著了.而恰恰xxx的文本阅读就是依赖于PageBitmap. PageBitmap是创建屏幕分辨率大小的Bitmap,虽然有封装了一个池BitmapPool来管理PageBitmap的创建和销毁,以及引用.但是还是没发完全避免由于PageBitmap所带来的内存溢出.并且TextViewerActivity, TextDraw, TXTParagraph, ParagraphLineData, ParagraghData, TXTReader之间错综复杂的调用关系以及引用,决定了在TextViewerActivity中创建的对象并没有完全的释放,容易发生内存溢出.

有效的解决内存溢出:

1.及时的销毁.

虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制.因此,在用完Bitmap时,要及时的recycle掉.recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:”该图片可以释放了”.

2.设置一定的采样率.

有时候,我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存.

但像上面xxx中出现的问题,并不能简单的应用采样率来解决.那就要更深一步分析Bitmap在TextDraw中使用的情况,包括BitmapPool中缓存PageBitmap数量以及对象的引用情况.

5.  Cursor

Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉.然而如果Cursor的数据量特表大,特别是如果里面有Blob信息时,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理.并且Android明显是倾向于手动的将Cursor close掉. 有一种情况下,我们不能直接将Cursor关闭掉,这就是在CursorAdapter中应用的情况,但是注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭.

【转载】Android 内存溢出如何发生的。的更多相关文章

  1. Android 内存溢出处理方案

    转自 : http://www.cnblogs.com/hello-ruby/archive/2013/04/19/3031098.html 首先我们来看看android内存溢出的原因,有可能是: 由 ...

  2. android 内存溢出问题分析

      最近的项目中,内存一直再增长,但是不知道是什么问题,导致内存溢出,在网上看到了这么一篇关于内存分析与管理的文章,解决了部分问题,感觉这篇文 章还不错,就转帖到我的blog上了,希望对大家有所帮助. ...

  3. Android内存溢出、内存泄漏常见案例及最佳实践总结

    内存溢出是Android开发中一个老大难的问题,相关的知识点比较繁杂,绝大部分的开发者都零零星星知道一些,但难以全面.本篇文档会尽量从广度和深度两个方面进行整理,帮助大家梳理这方面的知识点(基于Jav ...

  4. Android内存溢出解决方案(OOM)

    众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视平台而定).因此在开发应用时需要特别关注自身的内存使用量,而一般最耗内存量的资源,一般是图片.音频文 ...

  5. Android 内存溢出解决方案(OOM) 整理总结

    在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总 ...

  6. Android 内存溢出管理与测试

    今天发现正在做的项目,时不时的会报错:dalvikvm heap out of memory on a 7458832-byte allocation (堆分配的内存溢出) 为什么会内存溢出呢?我以前 ...

  7. Android 内存溢出解决方案(OOM) 整理总结<转>

    在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总 ...

  8. android 内存溢出与内存泄露

    内存溢出就是软件运行需要的内存,超出了java虚拟机给他分配的可用的最大内存 内存泄露就是在缓存图片文字等等的时候,没有关闭流所导致的内存泄露

  9. android 内存溢出oom错误的一些小见解

    转:http://blog.csdn.net/xuhui_7810/article/details/9493681 我们在代码里调用setBackgroundResource(int resid)来设 ...

随机推荐

  1. Web项目开发中常见安全问题及防范

    计算机程序主要就是输入数据 经过处理之后 输出结果,安全问题由此产生,凡是有输入的地方都可能带来安全风险.根据输入的数据类型,Web应用主要有数值型.字符型.文件型. 要消除风险就要对输入的数据进行检 ...

  2. java web项目用cookie记住用户名、密码

    1.jsp页面: <% String flag = (String)session.getAttribute("flag")==null?"":(Stri ...

  3. SSH整合(一)

    一.ssh原始整合方式 不需要任何整合包,就是简单的将三个框架集合到一起 hibernate        导入jar包:            hibernate-release-5.0.7.Fin ...

  4. 小程序OSS图片上传

    图片上传加水印问题,代码如下! chooseImage: function (e) { var that = this; wx.chooseImage({ sizeType: ['original', ...

  5. MySQL学习之用户管理

    用户权限管理 用户权限管理:在不同的项目中给不同的角色(开发者)不同的操作权限,为了保证数据库数据的安全. 简单点说:有的用户可以访问并修改这个数据,而有些用户只能去查看数据,而不能修改数据.就如同博 ...

  6. PHP读取excel

    $file = '';//文件名称 $file_ext = explode('.',$file);$file_ext = $file_ext[1];$data['file_ext'] = $file_ ...

  7. 【laravel】passport的scope作用域

    1.根据作用域生成token $user->createToken($request->name,['test1'])->accessToken; 2.注册中间件 'scopes' ...

  8. Java常用容器对比

    ArrayList与Vector ArrayList和Vector内部都是由数组实现的,数组实现的优点就是支持元素的随机访问(O(1)),但是在对元素进行插入和删除操作时,需要向后或向前移动数组,这样 ...

  9. Python3简单登录接口编写及遇到的问题分享

    1.程序目标 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 2.思路 利用python中的pickle模块,实现用户登录信息(采用dict)和被锁定用户信息(采用list)的存储.所以我预先 ...

  10. 【Android】添加依赖包

    貌似好像不知一种方法,以后有时间再研究,下面是其中的一种方法