内存泄漏(Memory Leak)
什么情况下会导致内存泄露(Memory Leak)?
Android 的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用
的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory 的错误。
内存溢出的几点原因:
1、资源释放问题
程序代码的问题,长期保持某些资源,如Context、Cursor、IO 流的引用,资源得不到释放造成内存泄露。
需要适当的释放资源的情况,这些硬件资源可能包括:视频、音频、相机等。
2、广播注册后没取消造成的内存泄漏
记得在activity销毁的时候一定要取消广播的注册
3、static 关键字的使用问题
static 是Java 中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。
所以用static 修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context 的情况最多),
这时就要谨慎对待了。
public class ClassName {
private static Context mContext;
//省略
}
以上的代码是很危险的,如果将Activity 赋值到mContext 的话。那么即使该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 也没有得到释放,发生了内存泄露。
针对static 的解决方案
① 应该尽量避免static 成员变量引用资源耗费过多的实例,比如Context。
② 此时的Context 尽量使用ApplicationContext,因为Application 的Context 的生命周期比较长,引用它不会出现内存泄露的问题。
③ 使用WeakReference 代替强引用。比如可以使用WeakReference<Context> mContextRef;
4、线程导致内存溢出
线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new MyThread().start();
}
private class MyThread extends Thread{
@Override
public void run() {
super.run();
//do somthing
}
}
}
这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread 的run 函数是一个很费
时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我
们的想法,老的Activity 应该会被销毁才对,然而事实上并非如此。
由于我们的线程是Activity 的内部类,所以MyThread 中保存了Activity 的一个引用,当MyThread 的run 函
数没有结束时,MyThread 是不会被销毁的,因此它所引用的老的Activity 也不会被销毁,因此就出现了内存泄露的问题。
有些人喜欢用Android 提供的AsyncTask,但事实上AsyncTask 的问题更加严重,Thread 只有在run 函数不结
束时才出现这种内存泄露问题,然而AsyncTask 内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread 对
象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask 作为Activity 的内部类,就更容易出现内存泄露的问题。
针对这种线程导致的内存泄露问题的解决方案:
① 将线程的内部类,改为静态内部类(因为非静态内部类拥有外部类对象的强引用,而静态类则不拥有)。
②在线程内部采用弱引用保存Context 引用。
5、Handler内存泄漏
Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:
① 在onDestroy里移除msg或callback
② 声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放
③ 如果内部类实在需要用到外部类的对象,可在其内部声明一个弱引用引用外部类。
6、使用application的context来替代activity
这是一个很隐晦的内存泄漏的情况。有一种简单的方法来避免context相关的内存泄漏,最显著地一个是避免context逃出他自己的范围之外,使用Application context,这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。
7、集合中对象没清理造成的内存泄漏
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。
如果这个集合是static的话,那情况就更严重了。
附:
1.微信团队原创分享:Android内存泄漏监控和优化技巧总结
内存泄漏(Memory Leak)的更多相关文章
- 堆(heap)和栈(stack)、内存泄漏(memory leak)和内存溢出
来源:http://blog.itpub.net/8797129/viewspace-693648/ 简单的可以理解为:heap:是由malloc之类函数分配的空间所在地.地址是由低向高增长的.sta ...
- Android 内存管理 &Memory Leak & OOM 分析
转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...
- 内存溢出(Oom)和内存泄露(Memory leak)
1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...
- SQL Server 内存泄露(memory leak)——游标导致的内存问题
原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...
- 内存泄漏 Memory Leaks 内存优化 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- malloc(50) 内存泄露 内存溢出 memory leak会最终会导致out of memory
https://en.wikipedia.org/wiki/Memory_leak In computer science, a memory leak is a type of resource l ...
- 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别
内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...
- python内存泄露memory leak排查记录
问题描述 A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的. 针对每个集群,主线程会创建一个子线程,并由子线程去检测.子线程会频繁的创建和销毁. 上线以后,由于经常会有 ...
- 利用linux的mtrace命令定位内存泄露(Memory Leak)
一谈到内存泄露, 多数程序猿都闻之色变. 没错, 内存泄露非常easy引入. 但非常难定位. 以你我的手机为例(如果不常常关机). 如果每天泄露一些内存, 那么開始的一个星期, 你会发现手机好好的. ...
随机推荐
- sleep、yield、join方法简介与用法 sleep与wait区别 多线程中篇(十五)
Object中的wait.notify.notifyAll,可以用于线程间的通信,核心原理为借助于监视器的入口集与等待集逻辑 通过这三个方法完成线程在指定锁(监视器)上的等待与唤醒,这三个方法是以锁( ...
- Java基础系列-Enum深入解析
原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755129.html 一.概述 枚举就是一个语法糖效果. 定义一个枚举,其实就是定义一个继承抽象类E ...
- 在java中如何实现字符串的反转
如 "abcdt" 反转之后是 "tdcba" 思路1: 运用递归的方法进行反转 假设反转方法为 reverseString(String str)1)当字符串 ...
- 单机Qps上限是多少?
现在这个年代,你要是不懂高并发,你都不好意思说自己是搞互联网的! 一.什么是并发,什么是高并发 并发,两个及以上的行为一起发生,比如你一边吃饭一边看电视 高并发,多个行为(至于是多少,这个没有定数,你 ...
- Django学习之十一:真正理解Django的路由分发和反解url原理
目录 URL Dispatcher 简介 模式概念 对比URLPattern 与 URLResolver (多态的体现) 构建子路由几种方式 反解url算法逻辑 URL Dispatcher 简介 d ...
- 我的世界 ParaCraft 结合开源地图 OpenStreetMap 生成3D校园的方法简介
我的世界ParaCraft结合开源地图OpenStreetMap生成3D校园的方法简介 版本1.0 日期2019.2.3 作者Ray (82735589@qq.com) www.TimeGIS.com ...
- Git的安装与配置
在安装Git之前,首先要下载Git安装包. 下载地址:https://gitforwindows.org/ 下载完后打开安装:如下步骤 按着以上步骤安装完成 ...
- go语言框架gin之集成swagger
1.安装swag 在goLand中直接使用go get -u github.com/swaggo/swag/cmd/swag命令安装会报错 翻了很多博客,都没找到太合适的办法,根据博客中所写的操作还是 ...
- Redmine入门-安装
Redmine提供了两种方式安装,如果仅仅只是使用Redmine,建议采用一键安装的方式,快捷方便.如果需要做二次开发或者更多的个性化处理,可以采用源码安装方式,下面分别介绍两种安装方式. ----- ...
- 关于SQL Server 数据库归档的一些思考和改进
一.需求背景 SQL Server开源的归档工具不多,DBA一般都是通过计划任务来触发执行,执行的脚本多是SP或者是SSIS包.SSIS包的性能稍好一些,但是维护更新成本高些.所以更常见的是通过SP脚 ...