内存泄漏和内存溢出的优化

内存泄漏: 对象在内存heap堆中中分配的空间, 当不再使用或没有引用指向的情况下, 仍不能被GC正常回收的情况。 多数出现在不合理的编码情况下, 比如在Activity中注册了一个广播接收器, 但是在页面关闭的时候进行unRegister, 就会出现内存溢出的现象。 通常情况下, 大量的内存泄漏会造成OOM

OOM: 即OutOfMemoery, 顾名思义就是指内存溢出了。 内存溢出是指APP向系统申请超过最大阀值的内存请求, 系统不会再分配多余的空间, 就会造成OOM error。 在我们Android平台下, 多数情况是出现在图片不当处理加载的时候。内存管理之道嘛, 无非就是先理解并找出内存泄漏的原因, 再基于这些反式去合理的编码, 去防范进而避免内存开销过大的情形。 学习如何合理的管理内存, 最好先了解内存分配的机制和原理。 只有深层次的理解了内部的原理, 才能真正避免OOM的发生。

Android APP的所能申请的最大内存大小是多少, 有人说是16MB, 有人又说是24MB。 这种事情, 还是亲自用自己的手机测试下比较靠谱。 测试方式也比较简单, Java中有个Runtime类, 主要用作APP与运行环境交互, APP并不会为我们创建Runtime的实例, 但是Java为我们提供了单例获取的方式Runtime.getRuntime()。 通过maxMemory()方法获取系统可为APP分配的最大内存, totalMemory()获取APP当前所分配的内存heap空间大小。 我手上有两部手机, 一部Oppo find7, 运行Color OS, 实测最大内存分配为192MB; 一部天语v9, 运行小米系统, 实测最大内存分配为100MB。 这下看出点眉目了吧, 由于Android是开源系统, 不同的手机厂商其实是拥有修改这部分权限能力的, 所以就造成了不同品牌和不同系统的手机, 对于APP的内存支持也是不一样的, 和IOS的恒久100MB是不同的。 一般来说, 手机内存的配置越高, 厂商也会调大手机支持的内存最大阀值, 尤其是现在旗舰机满天发布的情况下。 但是开发者为了考虑开发出的APP的内存兼容性, 无法保证APP运行在何种手机上, 只能从编码角度来优化内存了。


Android内存优化的关键点。

1、 万恶的static

static是个好东西, 声明赋值调用就是那么的简单方便, 但是伴随而来的还有性能问题。 由于static声明变量的生命周期其实是和APP的生命周期一样的, 有点类似与Application。 如果大量的使用的话, 就会占据内存空间不释放, 积少成多也会造成内存的不断开销, 直至挂掉。 static的合理使用一般用来修饰基本数据类型或者轻量级对象, 尽量避免修复集合或者大对象, 常用作修饰全局配置项、 工具类方法、 内部类。

2、 无关引用

很多情况下, 我们需求用到传递引用, 但是我们无法确保引用传递出去后能否及时的回收。 比如比较有代表性的Context泄漏, 很多情况下当Activity结束掉后, 由于仍被其他的对象指向导致一直迟迟不能回收, 这就造成了内存泄漏。 这时可以考虑第三条建议。

3、 善用SoftReference/WeakReference/LruCache

JavaAndroid中有没有这样一种机制呢, 当内存吃紧或者GC扫过的情况下, 就能及时把一些内存占用给释放掉, 从而分配给需要分配的地方。 答案是肯定的, java为我们提供了两个解决方案。 如果对内存的开销比较关注的APP, 可以考虑使用WeakReference, 当GC回收扫过这块内存区域时就会回收; 如果不是那么关注的话, 可以使用SoftReference, 它会在内存申请不足的情况下自动释放, 同样也能解决OOM问题。 同时Android3.0以后也推出了LruCache类, 使用LRU算法就释放内存, 一样的能解决OOM, 如果兼容3.0一下的版本, 请导入v4包。 关于第二条的无关引用的问题, 我们传参可以考虑使用WeakReference包装一下。

4、 谨慎handler

在处理异步操作的时候, handler + thread是个不错的选择。 但是相信在使用handler的时候, 大家都会遇到警告的情形, 这个就是lint为开发者的提
醒。 handler运行于UI线程, 不断处理来自MessageQueue的消息, 如果handler还有消息需要处理但是Activity页面已经结束的情况下, Activity
的引用其实并不会被回收, 这就造成了内存泄漏。 解决方案, 一是在ActivityonDestroy
方法中调用
handler.removeCallbacksAndMessages(null);取消所有的消息的处理, 包括待处理的消息; 二是声明handler的内部类为static

5Bitmap终极杀手

Bitmap的不当处理极可能造成OOM, 绝大多数情况都是因这个原因出现的。 Bitamp位图是Android中当之无愧的胖小子, 所以在操作的时候当然是十分的小心了。 由于Dalivk并不会主动的去回收, 需要开发者在Bitmap不被使用的时候recycle掉。 使用的过程中, 及时释放是非常重要的。 同时如果需求允许, 也可以去BItmap进行一定的缩放, 通过BitmapFactory.OptionsinSampleSize属性进行控制。 如果仅仅只想获得Bitmap的属性, 其实并不需要根据BItmap的像素去分配内存, 只需在解析读取Bmp的时候使用BitmapFactory.OptionsinJustDecodeBounds属性。 最后建议大家在加载网络图片的时候, 使用软引用或者弱引用并进行本地缓存, 推荐使用android-universal-imageloader或者xUtils, 牛人出品, 必属精品。 前几天在讲《 自定义控件( 三) 继承控件》 的时候, 也整理一个, 大家可以去Github下载看看。

6Cursor及时关闭

在查询SQLite数据库时, 会返回一个Cursor, 当查询完毕后, 及时关闭, 这样就可以把查询的结果集及时给回收掉。

7、 页面背景和图片加载

在布局和代码中设置背景和图片的时候, 如果是纯色, 尽量使用color; 如果是规则图形, 尽量使用shape画图; 如果稍微复杂点, 可以使用9patch图; 如果不能使用9patch的情况下, 针对几种主流分辨率的机型进行切图。

8ListViewGridViewitem缓存

对于移动设备, 尤其硬件参差不齐的android生态, 页面的绘制其实是很耗时的, findViewById也是蛮慢的。 所以不重用View, 在有列表的时候就尤为显著了, 经常会出现滑动很卡的现象。 具体参照历史文章《 说说ViewHolder的另一种写法》

9BroadCastReceiverService

绑定广播和服务, 一定要记得在不需要的时候给解绑。

10I/O

I/O流操作完毕, 读写结束, 记得关闭。

11、 线程

线程不再需要继续执行的时候要记得及时关闭, 开启线程数量不易过多, 一般和自己机器内核数一样最好, 推荐开启线程的时候, 使用线程池。

12String/StringBuffer

当有较多的字符创需要拼接的时候, 推荐使用StringBuffer


 内存溢出

在安卓的应用程序中,内存溢出主要提要在几个方面

1.ListView的显示

我们在使用ListView的时候,都会给他设置Adapter,如果在Adapter中的getView方法 中,我们没有复用convertView,就会造成在滑动ListView的时候,会为每一个item都 生成一个View对象,而不管这个item之前是否已经生成过View对象。如果来回滑动 的次数太多的话,就会造成View生成的数量太多,最终会造成内存溢出。

如果ListView中的item是包含图片的,那么,如果在快速滑动的过程中,我们就去为item加载图片,此时非常容易造成内存溢出。因为,在快速滑动的过程中,垃圾回收器还来不及回收内存,而新的item又需要新的内存来显示图片。所以,在这种情况下,一般的做法是监听ListView的滚动状态,当ListView的滚动状态为空闲的情况下,里面 的每一个Item才去加载图片。

2.加载图片相关

a、加载多张图片

对于加载多张图片,我们一般会使用三级缓存来实现图片的加载。内存缓存、本地缓存、网络缓存。缓存的目的是为了下一次加载速度更快。所以在内存中保存着一定数量的图片是有助于下一次图片显示的速度。但是,内存中不能保存太多的图片对象,所以我们使用LRUCache来保存内存中的图片,并且控制在一定的数量之内。

b、加载单张图片

这种情况是针对于某一张图片特别大的情况。如果一张图片非常非常大,如果50M,那么我只要一去加载它,那么我的程序肯定就会挂,根本还没使用到三级缓存应用程序就受不了了。所以,对于大图片的显示需要特殊处理。因为图片虽然特别大,但是这个图片所需要显示的控件有可能是很小的。我们可以先把图片的宽和高得到,再得到这张图片所需要显示的控件的宽高,就可以得到图片和控件的缩放比例了。最后,根据缩放比例,设置图片的采样率,来减小单张图片的内存占用。


解决方案

无论是内存泄露还是内存溢出,最终的后果基本上是一致的,那就是造成应用程序强行关闭。在应用程序的功能开发完之后,怎么样才能确定应用程序有没有内存的问题呢?又怎样来确定到底是哪一块代码出的问题呢?接下来我们就来说说关于内存问题的解决方案。

1、使用monkey工具

因为有些内存问题藏的比较深,要长期使用才能出现异常。所以可以使用monKey工具 来对我们的应用程序进行压力测试。

模拟200000次用户操作的参考命令: adb shell monkey -s 23 -p cn.itcast.XXX(所测试的 包) --ignore-crashes --ignore-timeouts -v -v -v 200000 > D:\文件名.log

回车之后,我们所需要测试的应用程序就启动了,并且还有不断触摸事件被促发,程序 生成的log会保存在D目录下。

2、捕获OOM异常

自定义Application并让它实现UncaughtExceptionHandler 接口,在onCreate方法中让自己成为系统的默认异常处理机制。Thread.setDefaultUncaughtExceptionHandler(this);

这样子设置之后,如果应用程序出现异常,就会调用Application中的uncaughtException 方法。我们就在这个方法中判断异常是否为OOM异常。如果是OOM异常,就将内存快照导到sd卡中去。

3.用第三方开源框架分析

leakcanary 是一个开源项目,一个内存泄露自动检测工具,是著名的 GitHub 开源组织 Square 贡献的,它的主要优势就在于自动化过早的发觉内存泄露、配置简单、抓取贴心,缺点在于还存在一些bug,不过正常使用百分之九十情况是OK的,其核心原理与MAT工具类似。

转载于:https://www.cnblogs.com/loaderman/p/6438371.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用ftp搭建yum源问题解决

wget 无法连接的情况 关闭linux 防火墙 1) 重启后生效 开启: chkconfig iptables on 关闭: chkconfig iptables off 2) 即时生效,重启后失效 开启: service iptables start 关闭: service iptables stop 需要说明的是对…

oracle文件

1、控制文件和日志文件 控制文件(Control File)是一个很小的二进制文件,用于描述和维护数据库的物理结构。在Oracle数据库中,控制文件相当重要,它存放有数据库中数据文件和日志文件的信息。Oracle数据库在启动时需要访…

Javascript this关键字 指向详解

Javascript this关键字 指向详解 面向对象语言中 this 表示当前对象的一个引用。在 JavaScript 中 this 不是固定不变的&#xff0c;它会随着执行环境的改变而改变。 1&#xff09; 单独使用&#xff0c;this 表示全局对象。 <script type"text/javascript">…

storyboard隐藏iphone软键盘

xcode 4.3.2 storyboard ** 点击软键盘的return键隐藏软键盘 .h文件定义IBAction -(IBAction)textFieldReturn:(id)sender; .m文件实现 -(IBAction)textFieldReturn:(id)sender{[sender resignFirstResponder];//关键代码 } storyboard中&#xff0c;选中文本框&#xff0c;查…

常用命令-tar 加密

2019独角兽企业重金招聘Python工程师标准>>> 在当前目录下有一个pma目录的文件夹: 1、使用tar对文件压缩加密&#xff1a; # tar -zcvf - pma|openssl des3 -salt -k password | dd ofpma.des3 完成将得到一个pma.des3的打包文件&#xff0c;用你设置的密码替换pas…

ORM SQLAlchemy 简介

对象关系映射&#xff08;Object Relational Mapping&#xff0c;简称ORM使用DB-API访问数据库&#xff0c;需要懂 SQL 语言&#xff0c;能够写 SQL 语句&#xff0c;如果不想懂 SQL&#xff0c;又想使用关系型数据库&#xff0c;可以使用 ORM,一个 ORM , 它的一端连着 Databas…

Javascript let和const

Javascript let和const 在 ES6 之前&#xff0c;JavaScript 只有两种作用域&#xff1a; 全局变量 &#xff1a; 在函数外声明的变量作用域是全局的 局部变量&#xff08;函数变量&#xff09;&#xff1a;在函数内声明的变量作用域是局部的 <script type"text/jav…

Javascript JSON格式

Javascript JSON格式 1&#xff09;什么是JSON&#xff08;JavaScript Object Notation&#xff09;&#xff1f; 是一种轻量级的数据交换格式 是独立的语言 2&#xff09;JSON 语法规则 数据为 键/值 对 数据由逗号分隔 大括号保存对象 方括号保存数组 JSON 对象&#xff…

转:OAUTH协议简介

OAUTH协议简介 原文链接 摘要&#xff1a;OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第 三方触及到用户的帐号信息&#xff08;如用户名与密码&#xff09;&#xff0c;即第三方无需使用用户的用户名与密…

生产库自动派送报表派送失败之重新派送

/*Description: 生产库自动派送报表派送失败之重新派送 */USE [DB] --Replace yourDBGODECLARE ProductDate nvarchar(10) N2014-01-01DECLARE FactoryCode nvarchar(10) NXDECLARE strSQL nvarchar(3000)DECLARE strCRLF nvarchar(…

java集合框架05——ArrayList和LinkedList的区别

前面已经学习完了List部分的源码&#xff0c;主要是ArrayList和LinkedList两部分内容&#xff0c;这一节主要总结下List部分的内容。 List概括 先来回顾一下List在Collection中的的框架图&#xff1a; 从图中我们可以看出&#xff1a; 1. List是一个接口&#xff0c;它继承与Co…

Javascript 函数详解

Javascript 函数详解 1&#xff09;函数声明&#xff1a; 通过关键字function定义&#xff0c;把函数作为变量来声明 函数声明后不会立即执行&#xff0c;会在我们需要的时候调用到。 <script>function myFunction(a, b) {return a * b;}// js对大小写敏感&#xff0c;…

asp.net仿搜索引擎关键字高亮.搜索高亮

以前做关键字高亮都是直接使用replace方法直接替换 如 string input"AAbCC"; string keyword"b"; inputinput.ToUpp(); keywordkeyword.ToUpp(); ss.Replace(keyword,"<font>"keyword"</font>"); 如果这样 输出: "AA…

easyui validatebox 验证类型

required: "必选字段", remote: "请修正该字段", email: "请输入正确格式的电子邮件", url: "请输入合法的网址", date: "请输入合法的日期", dateISO: "请输入合法的日期 (ISO).&…

SSL 1461——最大连续数列的和

Description 求最大连续子序列的和 Input 第一行输入n(n<500),第二行为n个以空格分开的整数(-1000到1000之间)&#xff1b; Output 该序列中最大的连续子序列的和 Sample Input &#xff16;   1 2 -5 6 7 8 Sample Output 21 每次读入一个数判断它是否为负数&#xff0…

ln链接使用

首先说明下Linux下删除、移动、复制的意义。删除:是将inode表放回空闲区由1变为0&#xff0c;还可以找回文件移动:是将inode表不变&#xff0c;将文件转移至对应条目&#xff0c;删除原条录。同分区上操作速度快&#xff0c;不同分区相当于创建、删除原文件复制:是重建inode表&…

poj 2886Who Gets the Most Candies?

题目连接&#xff1a;http://poj.org/problem?id2886 这道题是模拟约瑟夫环&#xff0c;其具体实现和poj2826差不多的。 我的代码如下&#xff1a; #include<cstdio> #include<cstdlib> #include<cmath> #include<memory.h> int seg_tree[500010<&…

Javascript 对象一(对象详解)

JS创建对象的几种方法1. Object 构造函数 创建 2. 对象字面量表示法 创建 3. 使用工厂模式创建对象 在 Car 函数中&#xff0c;返回的是一个对象。那么我们就无法判断返回的对象究竟是一个什么样的类型。于是就出现了第四种创建对象的模式 4. 使用构造函数创建对象 构造函数…

有一个长为n的数组A,求满足0≤a≤bn的A[b]-A[a]的最大值。 给定数组A及它的大小n,请返回最大差值。...

// ConsoleApplication10.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <vector> #include <list> #include <deque> #include <string> #include <algorithm> using namespace st…

【BZOJ】1649: [Usaco2006 Dec]Cow Roller Coaster(dp)

http://www.lydsy.com/JudgeOnline/problem.php?id1649 又是题解。。。 设f[i][j]表示费用i长度j得到的最大乐趣 f[i][end[a]]max{f[i-cost[a][begin[a]]w[a]} 当f[i-cost[a][begin[a]]可行时 初始化f-1 f[0][0]0 #include <cstdio> #include <cstring> #include …