Android减少内存与内存泄露(1)
Android减少内存与内存泄露(1)
Java编程中经常容易被忽视,但本身又十分重要的一个问题就是内存使用的问题。Android应用主要使用Java语言编写,因此这个问题也同样会在Android开发中出现。Android主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存是比较有限的。如果我们编写的代码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机。为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。一方面,如果程序在运行过程中出现了内存泄漏的问题,仅仅会使得自己的进程被kill掉,而不会影响其他进程(如果是system_process等系 进程出问题的话,则会引起系统重启)。另一方面Android为不同类型的进程分配了不同的内存使用上限,如果应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉。
然而内存的消耗甚至泄露是不可避免的,那么首先只有养成良好的编程习惯,尽量做到减少内存的使用,尽可能的使垃圾内存得到回收,这才是解决问题的根本途径,那么我们该怎样编写代码呢?以下是本人的一些拙见以及网上达人们得一点点小小的建议:
(一) 查询数据库没有关闭游标
程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。我觉得可以这样做:
可以采取将cursor里的值赋值给实现Parcelable的类的成员变量,在所需要的地方相应取值便是,这样编可以做到及时关闭游标,释放资源。
(二) 构造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对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。ListView回收list item的view对象的过程可以查看:
android.widget.AbsListView.java –> void addScrapView(View scrap) 方法
(三) Bitmap对象不在使用时调用recycle()释放内存
有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。
(四) 将变量的作用域设置为最小
最小化作用域意味着对垃圾收集器更快的可见。让我们举一个例子。我们有一个变量定义在方法级,当方法执行完毕后,也就是说,控制跳出方法后,则该变量将不会被引用。这也就意味着它已经可以被垃圾回收。但是如果该变量是类级的,这时垃圾回收器就需要等待直到对该类的所有的引用都被
移除后才能进行垃圾回收。优化属性的作用域是必须的。同样这也是封装原则。最小化作用域降低了通过包访问变量并减少了耦合。
(五) 仅当你确实需要时才初始化
这个的意思是在你确实需要使用对象之前才分配内存。有些时候,需要在方法的开头定义一些属性。当定义这些属性时,我们很可能在定义它们的时候对其进行初始化。 这种情况下, 如果在首次使用之前出现任何问题 (如出现异常),那么已经初始化的变量所占用的内存就被浪费了。
(六) 不要在循环中定义变量
这是大部分内存溢出的程序中的另一个常见的错误。在循环中定义和初始化变量,对于循环的每次执行,该变量实例将在内存中创建并分配内存。在循环启动后,第一个对象已经可以回收了。这种额外的内存分配也会增加垃圾回收器的负担。看一下下面的代码片段你将很容易的找出问题所在。有些时候,
确实有必要在循环内定义变量,不过一定要小心使用。
(七) 不要在循环中定义变量
这是和 String 相关的一些东西,所有对 String 进行的操作都将产生另一个 String 对象。通常我们使用的 String 链接操作,这个需要注意,它会导致一个很长的动态的查询或产生一个 toString 方法中的 String。如果我们使用+操作符来连接字符串,这些额外的对象将根据+产生。当有过多操作的时候会变成很大的开销。使用不是不变对象,如 StringBuffer 来进行字符串链接操作。
(八) 不要在循环中定义变量
这会使得垃圾回收器的工作变得比较容易。 将重对象的引用设置为 null。这将释放对中对象的引用,使得垃圾回收器能立即释放它们占用的内存。
(九) 简单的使用 finally 块
finally 块即使 try 或 catch 执行不成功的时候也会执行,也就是说即使在 try 或 catch 中出现了任何异常,finally 块中的语句绝对也会执行。将清理内存的语句放在这里以保证内存被清理。
(十) 分散对象创建或删除的时间
集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增 加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机 会。
其他参考资料:http://doc.guandang.net/docs/toolbox/performance.html 按照以上的编程方法去写代码也许可以使你减少内存的消耗,防止内存泄露。然而当内存被慢慢的耗尽甚至出现内存泄露后,我们该怎么办呢?下面的论述也许对你定位内存泄露的原因以及找出正确的解决办法会有所帮助:
在介绍内存查看、分析工具之前,我想有必要先介绍一下相关的概念。
为何会内存溢出
我们知道JVM根据generation(代)来进行GC,根据下图所示,一共被分为young generation(年轻代)、tenured generation(老年代)、permanent
generation(永久代, perm gen),perm gen(或称Non-Heap 非堆)是个异类,稍后会讲到。注意,heap空间不包括perm gen。
当young generation的空间被填满,GC会进行minor collection(次回收),这次回收不涉及到heap中的其他generation,minor collection根据weak
generational hypothesis(弱年代假设)来假设young generation中大量的对象都是
垃圾需要回收,minor collection的过程会非常快。young generation中未被回收的对象被转移到tenured generation,然而tenured generation也会被填满,最终触发major collection(主回收),这次回收针对整个heap,由于涉及到大量对象,所以比minor collection慢得多。
JVM有三种垃圾回收器,分别是throughput collector,用来做并行yo …… 此处隐藏:8037字,全部文档内容请下载后查看。喜欢就下载吧 ……
- 基于PLC控制的航空电镀生产线自动输送
- 中考预测课内外文言文对比阅读2
- 2018-2023年中国商业智能(BI)产业市场
- 中国金融体制改革研究2011new
- 外窗淋水试验方案
- 精益生产(Lean Production)
- 学校安全事故处置和信息报送制度
- Chapter 5 Human Resources Management
- 【小学数学】人教版小学六年级上册数学
- 初中数学解题方法与技巧
- 山东省创伤中心建设与管理指导原则(试
- 函数与数列的极限的强化练习题答案
- 10分钟淋巴按摩消脂
- 网络应急演练预案
- 服装设计入门基础知识
- 初二数学分式计算题练习
- (人教新课标)高二数学必修5第二章 数列
- 最新自主创业项目
- 北京大学 无机化学课件 4第4章 配合物
- 贸易公司业务管理制度




