网站首页  词典首页

请输入您要查询的论文:

 

标题 基于Android的内存泄漏与溢出研究
范文 何群芳+时招军
摘 要:内存的泄漏与溢出是在进行Android开发时最常见且棘手的问题之一。为了提高Android开发的质量和效率,总结了Android的内存泄漏与溢出的常见类型和解决方法。内存泄漏的常见类型有集合类泄漏、传入Activity的Context造成的内存泄漏、非静态内部类创建静态实例和线程造成的内存泄漏等;内存溢出的常见类型有由强引用造成的内存溢出、由大量图片显示导致的内存溢出、从数据库中取出大量数据造成的内存溢出、代码中存在死循环或循环产生过多重复对象实体造成的内存溢出等,并提出了由图片造成的内存溢出的新的解决方法。
关键词:内存管理;Android;内存泄漏;内存溢出
DOIDOI:10.11907/rjdk.172379
中图分类号:TP301
文献标识码:A 文章编号:1672-7800(2018)002-0050-03
0 引言
Java的内存管理即为对象的分配和释放问题。在Java中,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),所有对象都在堆(Heap)中分配空间。而对象的释放由GC决定和执行。该方式确实简化了程序员的工作,但同时也加大了JVM的工作量。因为GC为了能够正确地释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等[1-4]。
在Java中,内存泄漏就是存在一些被分配的对象,这些对象存在以下两个特点:首先,这些对象是可达的,即在有向图中,存在通路可以与其相连(也即是说仍存在对该对象的引用);其次,这些对象是无用的,即程序以后不会再使用这些对象。如果满足这两个条件,这些对象即可判定为Java中的内存泄漏。内存泄漏造成的后果在于内存泄漏堆积,如果一直存在内存泄漏,最终会导致越来越多内存无法回收而又不能被利用,最终可用内存越来越少。内存溢出是程序占用的内存大小超过了虚拟机(DVM)的允许值,而造成内存溢出的最主要原因是高质量图片的大量出现。通过对Java内存分配、内存管理和垃圾回收原理的理解,总结导致内存泄漏和内存溢出的常见原因,并提出相应预防措施,可有效提升程序质量。
1 内存泄漏与内存溢出常见类型与解决方法
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果;内存溢出(Out of Memory)通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需的内存远远超出了主机内安装的内存所能承受的大小,称为内存溢出。此时软件或游戏无法运行,系统会提示内存溢出,有时甚至会自动关闭软件,重启电脑或软件后释放掉部分内存,又可以正常运行该软件。
1.1 内存泄漏常见类型与解决方法
1.1.1 集合类泄漏
集合类如果仅有添加元素的方法,而没有相应的删除机制,可能导致内存被占用。如果该集合类是全局性的变量 (比如类中的静态属性、全局性的 map 等即有静态引用或 final 一直指向它),则没有相应的删除机制,很可能导致集合占用的内存只增不减,这就是集合类泄漏。
解决方法:给集合类添加相应的删除机制,最简单的方法是直接将集合置为null。
1.1.2 传入Activity的Context造成的内存泄漏
因为Activity的生命周期可能比引用该Activity的生命周期短,所以即使该Activity被销毁,依然处于被引用状态,GC无法回收,造成内存泄漏。例如在static的工具类中,在创建数据库或打开数据库、开启系统服务与广播时以及创建单例等情况下传入Activity的Context,即使Activity被销毁,GC依然无法回收该Activity所占用的资源,这就是由传入Activity的Context造成的内存泄漏。
解决方法:如果需要传入Context,可以改用Application的Context,即getApplicationContext()。当然,Application的Context也不是万能的,基本上除了start a activity和show a dialog需要Activity的Context之外,其他的都可以用Application的Context替代。
1.1.3 非静态内部类创建静态实例与线程造成的内存泄漏
非静态内部类默认持有外部类的引用,而该非静态内部类又创建了一个静态实例,该实例的生命周期和应用长度相同,将导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。线程和非静态内部类相似。
解决方法:将非静态的内部类改为静态的内部类,并将对Activity的引用改为弱引用,使内部类和线程的生命周期脱离Activity的生命周期,并且当GC进行回收时,可以回收被弱引用的Activity等[5-8]。
1.2 内存溢出常见类型与解决方法
1.2.1 由强引用造成的内存溢出
若所有的引用都是强引用,则大量内存会被占用,最终导致内存溢出。
解決方法:使用弱引用或软引用,软引用的对象在内存不足时可被GC回收,弱引用的对象在垃圾回收时可被回收。
1.2.2 由大量图片显示导致的内存溢出
为解决由大量图片显示造成的内存溢出,可以使用BitmapFactory.Options类,在返回参数时,只返回Bitmap的尺寸大小,而不将其加载到内存中,可有效减少内存溢出。同时在加载完后调用system.gc()通知系统及时回收。
1.2.3 从数据库中取出大量数据造成的内存溢出
检查在数据库查询中,是否有一次获得全部数据的查询。一般而言,如果一次取十万条记录到内存,就可能引起内存溢出。该问题比较隐蔽,在上线前,数据库中数据较少,通常运行正常,上线后,数据库中数据增多,一次查询即有可能引起内存溢出。因此,对于数据库查询,尽量采用分页的方式查询。
1.2.4 代码中存在死循环或循环产生过多重复对象实体造成的内存溢出
出现这种情况,只能通过查看日志找出产生该问题的原因,检查代码中是否有死循环、递归调用,或大循环重复产生的新对象实体。
1.2.5 内存分配大小不够
虚拟机默认的内存大小对于大程序来说可能根本不够用,这时则需要手动更改默认的内存大小。对于Android平台而言,其托管层使用的Dalvik JavaVM从目前的表现看还有很多地方可以进行优化处理,比如在开发一些大型游戏或比较消耗资源的应用中可能考虑手动干涉GC处理,如使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率[9-11]。具体原理可以参考开源工程,使用方法代码如下:
Private final static float HEAP_UTILIZATION=0.6f;
//在程序onCreate时调用
VMRuntime.getRuntime().setTargetHeapUtilization(HEAP_UTILIZATION);
//自定义堆内存大小,如:
Private final static int HEAP_SIZE=8*1024*1024;
//设置最小堆内存大小为8MB
VMRuntime.getRuntime().setMininumHeapSize(HEAP_SIZE);
2 由圖片造成内存溢出的新解决方法与特点
2.1 解决方法
对于Android程序而言,大量高质量图片的显示几乎无法避免,这也是造成内存溢出最常见的原因之一。常见的解决方法是由程序员考虑到每一个可能造成内存溢出的情况,然后加以防范。但是若使用新组件RecyclerView,并改用RecyclerView.Adpter,则可以将由图片造成的内存溢出交由RecyclerView类解决。RecyclerView类主要关注的是资源的回收与重用。使用RecyclerView.Adpter的关键代码如下:
public class SimpleAdapter extends RecyclerView.Adapter{
/**
使用RecyclerView.Adapter重点在于重载这两个方法,第一个方法负责创建ViewHolder,第二个方法负责显示ViewHolder。只要将ViewHolder创建好,剩下资源的回收和重用RecyclerView会自动解决。
*/
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
}
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
}
另外,对于服务器上的图片,Android端可以直接使用路径访问,不需要从服务器端下载到客户端再进行显示。即使要缓存到Android本地,也可以直接保存路径。
2.2 特点
使用该方法,不仅可以让同一个fragment中的内容类型不一样,使单个页面的内容多元化,最主要的是RecyclerView不关心视图问题,中心放在回收和重用上。由RecyclerView直接进行资源的回收和利用,使程序员不需要再考虑是否会发生内存溢出,节省程序员在该方面花费的时间,提高程序编写效率。
3 结语
内存泄漏和内存溢出是Android开发中最为常见且繁琐的问题之一,在实际开发过程中想要彻底根除这两个问题几乎不可能,只能在编写代码时考虑全面,提前作好防范,养成良好的编程习惯,从而达到有效防止内存泄露和内存溢出的效果。通过对内存泄漏和内存溢出常见类型和解决方法的合理总结和归纳,可有效解决Android开发中遇到的一系列难点。
对内存的管理,关键在于资源的及时回收以及对内存泄漏的预防。内存的回收主要是对图片等其他对象的回收与利用。其中预防内存泄漏最主要的方法是将对Activity的Context的传入改为对Application的Context的传入,因为在很多UI界面以及广播等的使用过程中几乎都需要用到Context,而如果用Activity的Context,那么几乎整个应用程序中都会遍布Activity的Context,从而导致Activity无法成功销毁,最终导致内存泄漏。所以在需要传入Context时,一定要谨慎思考其可行性。另一种预防内存泄漏的方法是将对Activity的强引用改为弱引用或软引用,使GC在回收时,能成功回收该Activity所占用的内存资源。
参考文献:
[1] 周志明.深入理解Java虚拟机:JVM高级特性与最佳实践[M].第2版.北京:机械工业出版社,2013:50-98.
[2] 张秀宏.自己动手写Java虚拟机[M].北京:机械工业出版社,2016:60-98.
[3] 葛一鸣.实战Java虚拟机—JVM故障诊断与性能优化[M].北京:电子工业出版社,2015:30-45.
[4] 高翔龙.Java虚拟机精讲[M].北京:电子工业出版社,2015:88-98.
[5] 罗彧成.Android应用性能优化最佳实践[M].北京:机械工业出版社,2017:70-110.
[6] 埃尔韦.Android应用性能优化[M].白龙,译.北京:人民邮电出版社,2012:10-50.
[7] DOUG SILLARS.高性能Android应用开发[M].王若兰,周丹红,译.北京:人民邮电出版社,2016:98-119.
[8] 腾讯SNG专项测试团队.Android移动性能实战[M].北京:电子工业出版社,2017: 50-152.
[9] 钟世礼.深入解析Android虚拟机[M].北京:人民邮电出版社,2016:40-48.
[10] 张国印,吴艳霞. AndroidDalvik虚拟机结构及机制剖析[M].北京:清华大学出版社,2014:1-20.
[11] 张子言.深入解析Android虚拟机[M].北京:清华大学出版社,2014:50-90.
随便看

 

科学优质学术资源、百科知识分享平台,免费提供知识科普、生活经验分享、中外学术论文、各类范文、学术文献、教学资料、学术期刊、会议、报纸、杂志、工具书等各类资源检索、在线阅读和软件app下载服务。

 

Copyright © 2004-2023 puapp.net All Rights Reserved
更新时间:2025/2/6 4:44:55