【转载】Android 内存溢出如何发生的。
【转载】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 内存溢出如何发生的。的更多相关文章
- Android 内存溢出处理方案
转自 : http://www.cnblogs.com/hello-ruby/archive/2013/04/19/3031098.html 首先我们来看看android内存溢出的原因,有可能是: 由 ...
- android 内存溢出问题分析
最近的项目中,内存一直再增长,但是不知道是什么问题,导致内存溢出,在网上看到了这么一篇关于内存分析与管理的文章,解决了部分问题,感觉这篇文 章还不错,就转帖到我的blog上了,希望对大家有所帮助. ...
- Android内存溢出、内存泄漏常见案例及最佳实践总结
内存溢出是Android开发中一个老大难的问题,相关的知识点比较繁杂,绝大部分的开发者都零零星星知道一些,但难以全面.本篇文档会尽量从广度和深度两个方面进行整理,帮助大家梳理这方面的知识点(基于Jav ...
- Android内存溢出解决方案(OOM)
众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视平台而定).因此在开发应用时需要特别关注自身的内存使用量,而一般最耗内存量的资源,一般是图片.音频文 ...
- Android 内存溢出解决方案(OOM) 整理总结
在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总 ...
- Android 内存溢出管理与测试
今天发现正在做的项目,时不时的会报错:dalvikvm heap out of memory on a 7458832-byte allocation (堆分配的内存溢出) 为什么会内存溢出呢?我以前 ...
- Android 内存溢出解决方案(OOM) 整理总结<转>
在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总 ...
- android 内存溢出与内存泄露
内存溢出就是软件运行需要的内存,超出了java虚拟机给他分配的可用的最大内存 内存泄露就是在缓存图片文字等等的时候,没有关闭流所导致的内存泄露
- android 内存溢出oom错误的一些小见解
转:http://blog.csdn.net/xuhui_7810/article/details/9493681 我们在代码里调用setBackgroundResource(int resid)来设 ...
随机推荐
- 『ACM C++』 Codeforces | 1003C - Intense Heat
今日兴趣新闻: NASA 研制最强推进器,加速度可达每秒 40 公里,飞火星全靠它 链接:https://mbd.baidu.com/newspage/data/landingsuper?contex ...
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- python中的extend和append
list.append(object) 向列表中添加一个对象object list.extend(sequence) 把一个序列seq的内容添加到列表中 old = ['a', 'b'] new = ...
- SQL注入的浅尝辄止
简单的说,SQL注入就是通过在前端页面输入SQL语句,导致系统暴露异常信息在前端页面显示,非法者通过这些异常信息获取数据库的相干信息,为攻击系统做准备.
- form表单的一个页面多个上传按钮实例
/* * 图片上传 */ @RequestMapping("/uploadFile") @ResponseBody public String uploadFile(@Reques ...
- colspan和rowspan合并单元格
最近在回顾html的时候,经常碰到一些table标签的问题,其中大多数都是合并单元格,所以在这里记录下自己的探究过程: <table cellpadding="0" cell ...
- Java : logback简单配置
需要把logback.xml文件放在类路径下,如果是spring boot项目可以用 logging.config=classpath:log/xxxxxx.xml来指定配置文件 logback la ...
- 公司内部搭建git服务器
前言 因为gitHub上的项目是公开的,不适合公司内部项目放在上面,而私人的需要收费,这绝非是我们愿意的.所以找了个跟gitHub很相似,但是又免费的gitLab.现在将搭建gitLab过程记录一下留 ...
- 壹度DIY_微信小程序组件_小程序插件开发
开源免费插件,diy特有的页面机制,搭配30+自定义组件,让你的站点每一个页面都可以完全自定义,可无缝对接任意小程序,如有疑问加入qq壹度小程序交流群:302866773:或wx:liu2417301 ...
- day 21继承
1.了解Python2和python3类的区别: python2.3之前使用的是经典类, 在2.3版本之后组,使用的是新式类 MRO: method resolution order 方法的查找 ...