Android内存优化10 内存泄漏常见情况1 静态泄漏
1,内存泄漏到本质是该释放的对象被持久化的对象引用了,造成持久化的常见情况有1,静态持久化 2,线程持久化
线程持久化
因为存活的线程是有dvk虚拟久直接持有,所以存活的线程都是持久化的
内存泄漏1:静态Activities(static Activities)
代码如下:
MainActivity.Java
public class MainActivity extends AppCompatActivity {
private static MainActivity activity;
TextView saButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
saButton = (TextView) findViewById(R.id.text);
saButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setStaticActivity();
nextActivity();
}
});
}
void setStaticActivity() {
activity = this;
}
void nextActivity(){
startActivity(new Intent(this,RegisterActivity.class));
SystemClock.sleep(1000);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
//使用LeakCanary观察是否有内存泄漏
MyApplication.getRefWatcher().watch(this);
}
}
LeakCanary检测出的内存泄漏:
为什么?
在上面代码中,我们声明了一个静态的Activity变量并且在TextView的OnClick事件里引用了当前正在运行的Activity实例,所以如果在activity的生命周期结束之前没有清除这个引用,则会引起内存泄漏。因为声明的activity是静态的,会常驻内存,如果该对象不清除,则垃圾回收器无法回收变量。
怎么解决?
最简单的方法是在onDestory方法中将静态变量activity置空,这样垃圾回收器就可以将静态变量回收。
@Override
protected void onDestroy() {
super.onDestroy();
activity = null;
//使用LeakCanary观察是否有内存泄漏
MyApplication.getRefWatcher().watch(this);
}
不使用静态activity,或给静态activity赋值时,考虑赋值的activity生命周期是不是全局的,或者在静态activity使用完后及时释放
内存泄漏2:静态View
代码如下:
MainActivity.java
...
private static View view;
TextView saButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
saButton = (TextView) findViewById(R.id.text);
saButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setStaticView();
nextActivity();
}
});
}
void setStaticView() {
view = findViewById(R.id.sv_view);
}
...
LeakCanary检测到的内存泄漏
为什么?
上面代码看似没有问题,在Activity里声明一个静态变量view,然后初始化,当Activity生命周期结束了内存也释放了,但是LeakCanary却显示出现了内存泄漏,为什么?问题出在这里,View一旦被加载到界面中将会持有一个Context对象的引用,在这个例子中,这个context对象是我们的Activity,声明一个静态变量引用这个View,也就引用了activity,所以当activity生命周期结束了,静态View没有清除掉,还持有activity的引用,因此内存泄漏了。
怎么解决?
在onDestroy方法里将静态变量置空。
@Override
protected void onDestroy() {
super.onDestroy();
view = null;
MyApplication.getRefWatcher().watch(this);
}
不使用静态view,或在activity关闭时将静态view赋值为null
内存泄漏3:静态内部类
代码如下:
MainActivity.java
private static Object inner;
void createInnerClass() {
class InnerClass {
}
inner = new InnerClass();
}
View icButton = findViewById(R.id.ic_button);
icButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
createInnerClass();
nextActivity();
}
});
使用LeakCanary检测到的内存泄漏:
为什么?
非静态内部类会持有外部类的引用,在上面代码中内部类持有Activity的引用,因此inner会一直持有Activity,如果Activity生命周期结束没有清除这个引用,这样就发生了内存泄漏。
怎么解决?
因为非静态内部类隐式持有外部类的强引用,所以我们将内部类声明成静态的就可以了。
void createInnerClass() {
static class InnerClass {
}
inner = new InnerClass();
}
内存泄漏3:静态Drawable
当一个Drawable附加到一个 View上时,
View会将其作为一个callback设定到Drawable上。意味着Drawable拥有一个View的引用,上面说了view会有上下文的引用
内存泄漏4:静态集合中对象没清理造成的内存泄漏
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
内存泄漏5:单例导致内存泄露
单例模式在Android开发中会经常用到,但是如果使用不当就会导致内存泄露。因为单例的静态特性使得它的生命周期同应用的生命周期一样长,如果一个对象已经没有用处了,但是单例还持有它的引用,那么在整个应用程序的生命周期它都不能正常被回收,从而导致内存泄露。
public class AppSettings {
private static AppSettings sInstance;
private Context mContext;
private AppSettings(Context context) {
this.mContext = context;
}
public static AppSettings getInstance(Context context) {
if (sInstance == null) {
sInstance = new AppSettings(context);
}
return sInstance;
}
}
像上面代码中这样的单例,如果我们在调用getInstance(Context context)方法的时候传入的context参数是Activity、Service等上下文,就会导致内存泄露。
以Activity为例,当我们启动一个Activity,并调用getInstance(Context context)方法去获取AppSettings的单例,传入Activity.this作为context,这样AppSettings类的单例sInstance就持有了Activity的引用,当我们退出Activity时,该Activity就没有用了,但是因为sIntance作为静态单例(在应用程序的整个生命周期中存在)会继续持有这个Activity的引用,导致这个Activity对象无法被回收释放,这就造成了内存泄露。
为了避免这样单例导致内存泄露,我们可以将context参数改为全局的上下文:
private AppSettings(Context context) {
this.mContext = context.getApplicationContext();
}
全局的上下文Application Context就是应用程序的上下文,和单例的生命周期一样长,这样就避免了内存泄漏。
单例模式对应应用程序的生命周期,所以我们在构造单例的时候尽量避免使用Activity的上下文,而是使用Application的上下文。
Android内存优化10 内存泄漏常见情况1 静态泄漏的更多相关文章
- Android内存优化12 内存泄漏常见情况3 注册泄漏
android 中有很多注册和反注册,由于在注册后,上下文自身会被持久化的观察者列表所持有,如果不进行反注册,就会造成内存泄漏 内存泄漏1:Sensor Manager 代码如下: MainActiv ...
- Android内存优化11 内存泄漏常见情况2 内部类泄漏
线程持久化 Java中的Thread有一个特点就是她们都是直接被GC Root所引用,也就是说Dalvik虚拟机对所有被激活状态的线程都是持有强引用,导致GC永远都无法回收掉这些线程对象,除非线程被手 ...
- Android内存优化13 内存泄漏常见情况4 资源泄漏
资源未关闭或释放导致内存泄露 在使用IO.File流或者Sqlite.Cursor等资源时要及时关闭.这些资源在进行读写操作时通常都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放, ...
- Android 性能优化之内存泄漏检测以及内存优化(中)
https://blog.csdn.net/self_study/article/details/66969064 上篇博客我们写到了 Java/Android 内存的分配以及相关 GC 的详细分析, ...
- 老李分享:Android性能优化之内存泄漏1
老李分享:Android性能优化之内存泄漏 前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我 ...
- [Android 性能优化系列]内存之提升篇--应用应该怎样管理内存
大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处(http://blog.csdn.net/kifile),再次感谢 原文地 ...
- [Android 性能优化系列]内存之基础篇--Android怎样管理内存
大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处(http://blog.csdn.net/kifile),再次感谢 原文地 ...
- Android性能优化之内存篇
下面是内存篇章的学习笔记,部分内容与前面的性能优化典范有重合,欢迎大家一起学习交流! 1)Memory, GC, and Performance 众所周知,与C/C++需要通过手动编码来申请以及释放内 ...
- Android内存优化9 内存检测工具3 MAT比Menmery Monitor更强大
在Android性能优化第(一)篇---基本概念中讲了JAVA的四大引用,讲了一下GCRoot,第二篇Memory Monitor检测内存泄露仅仅说了Menmery Monitor的使用,这篇博客谈一 ...
随机推荐
- Python的web服务器
1.浏览器请求动态页面过程 2.WSGI Python Web Server Gateway Interface (或简称 WSGI,读作“wizgy”). WSGI允许开发者将选择web框架和web ...
- 流程控制--while
/* while 是在有条件控制的情况下 进行的循环 */ [root@localhost test1]# vim .py //ADD #!/usr/bin/python n = while True ...
- C++中delete和delete[]的区别(转)
原文链接:http://www.cnblogs.com/charley_yang/archive/2010/12/08/1899982.html 一直对C++中的delete和delete[]的区别不 ...
- 关于那些Android中不常用的设置属性
很多在manifest中的属性我们经常遗忘了它们,或者经常看到但又不是很明白它的作用.那么在这里我就拿了一些属性简单的解释一下,防止以后碰到却不知道其中的意思.不是很全,以后会断断续续的补充吧 一.a ...
- vue 计算属性 实例选项 生命周期
vue 计算属性: computed:{} 写在new vue()的属性,只要参与运算,数据不发生变化时,次计算只会执行一次,结果缓存,之后的计算会直接从缓存里去结果.如果其中的值发生变化(不管几个) ...
- Idea创建模板
新建文件模板 /** * * @author zenglw * @date ${DATE} */ Mapper #if (${PACKAGE_NAME} && ${PACKAGE_NA ...
- 数据库SQL调优之"执行计划"【未完待续】
什么是“执行计划”?“执行计划”怎么用于SQL调优? 内容待添加... 参考文章: [1]写SQL要学会使用"执行计划" by 鹏霄万里展雄飞
- 620. Not Boring Movies
X city opened a new cinema, many people would like to go to this cinema. The cinema also gives out a ...
- 寻找与网页内容相关的图片(三)网易新闻与qq空间的做法
寻找与网页相关的图片现在看来无非有两种方式,第一种是网页自己指定,第二种是通过算法推断. 对于网站的内容提供者来说,他自己知道相关的图片在哪,正如前文所述可以在HTML的头部加上META标签,也可以像 ...
- 前端读者 | Javascript设计模式理论与实战:状态模式
本文来自 @狼狼的蓝胖子:链接:http://luopq.com/2015/11/25/design-pattern-state/ 在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将 ...