提兵百万西湖上,立马吴山第一峰!这篇文章主要讲述Android 如何有效的解决内存泄漏的问题相关的知识,希望能为你提供帮助。
https://www.cnblogs.com/zhaoyanjun/p/5981386.html
前言:最近在研究Handler的知识,其中涉及到一个问题,如何避免Handler带来的内存溢出问题。在网上找了很多资料,有很多都是互相抄的,没有实际的作用。
本文的内存泄漏检测工具是:LeakCanary
github地址:https://github.com/square/leakcanary
什么是内存泄漏?
- 内存泄漏是当程序不再使用到的内存时,释放内存失败而产生了无用的内存消耗。内存泄漏并不是指物理上的内存消失,这里的内存泄漏是值由程序分配的内存但是由于程序逻辑错误而导致程序失去了对该内存的控制,使得内存浪费。
怎样会导致内存泄漏?
- 资源对象没关闭造成的内存泄漏,如查询数据库后没有关闭游标cursor
- 构造Adapter时,没有使用 convertView 重用
- Bitmap对象不在使用时调用recycle()释放内存
- 对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
内存泄漏有什么危害?
- 内存泄漏对于app没有直接的危害,即使app有发生内存泄漏的情况,也不一定会引起app崩溃,但是会增加app内存的占用。内存得不到释放,慢慢的会造成app内存溢出。所以我们解决内存泄漏的目的就是防止app发生内存溢出。
1、新建线程引起的Activity内存泄漏
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package rxnet.zyj.com.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public
class
Activity6 extends AppCompatActivity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_6);
findViewById( R.id.finish).setOnClickListener( new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
finish();
}
});
new
Thread( new
Runnable() {
@Override
public
void
run() {
try
{<
br>
//模拟耗时操作
Thread.sleep( 15000 );
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
} |
文章图片
为什么Activity6会发生内存泄漏?进入Activity6 界面,然后点击finish按钮,Activity6销毁,但是Activity6里面的线程还在运行,匿名内部类Runnable对象引用了Activity6的实例,导致Activity6所占用的内存不能被GC及时回收。
如何改进?Runnable改为静态非匿名内部类即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package rxnet.zyj.com.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public
class
Activity6 extends AppCompatActivity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_6);
findViewById( R.id.finish).setOnClickListener( new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
finish();
}
});
new
Thread(
new
MyRunnable()).start();
}
private
static
class
MyRunnable implements Runnable {
@Override
public
void
run() {
try
{
Thread.sleep( 15000 );
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
} |
2、Activity添加监听器造成Activity内存泄漏
1 2 3 4 5 6 7 8 9 10 11 12 | package rxnet.zyj.com.myapplication;
import android.app.Activity;
import android.os.Bundle;
public
class
LeakActivity extends Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NastyManager.getInstance().addListener( this );
}
} |
如何改进?想要修复这样的 Bug,其实相当简单,就是在你的 Acitivity 被销毁的时候,将他和 NastyManager 取消掉绑定就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package rxnet.zyj.com.myapplication;
import android.app.Activity;
import android.os.Bundle;
public
class
LeakActivity extends Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NastyManager.getInstance().addListener( this );
}
@Override
protected
void
onDestroy() {
super.onDestroy();
NastyManager.getInstance().removeListener( this );
}
} |
3、Handler 匿名内部类造成内存溢出?
先看着一段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package rxnet.zyj.com.myapplication;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
public
class
HandlerActivity extends AppCompatActivity {
private
final
static
int
MESSAGECODE = 1 ;
private
final Handler handler =
new
Handler(){
@Override
public
void
handleMessage(Message msg) {
super.handleMessage(msg);
Log.d( "mmmmmmmm"
,
"handler "
+ msg.what ) ;
}
};
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
findViewById( R.id.finish ).setOnClickListener( new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
finish();
}
});
new
Thread( new
Runnable() {
@Override
public
void
run() {
handler.sendEmptyMessage( MESSAGECODE ) ;
try
{
Thread.sleep( 8000 );
}
catch
(InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage( MESSAGECODE ) ;
}
}).start() ;
}
} |
如何避免
- 使用静态内部类
- 使用弱引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | package rxnet.zyj.com.myapplication;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import java.lang. ref .WeakReference;
public
class
HandlerActivity extends AppCompatActivity {
private
final
static
int
MESSAGECODE = 1 ;
private
static
Handler handler ;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
findViewById( R.id.finish ).setOnClickListener( new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
finish();
}
});
handler =
new
MyHandler(
this
) ;
new
Thread( new
Runnable() {
@Override
public
void
run() {
handler.sendEmptyMessage( MESSAGECODE ) ;
try
{
Thread.sleep( 8000 );
}
catch
(InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage( MESSAGECODE ) ;
}
}).start() ;
}
private
static
class
MyHandler extends Handler {
WeakReference<
HandlerActivity>
weakReference ;
public
MyHandler(HandlerActivity activity ){
weakReference
=
new
WeakReference<
HandlerActivity>
( activity) ;
}
@Override
public
void
handleMessage(Message msg) {
super.handleMessage(msg);
if
( weakReference. get () !=
null
){
// update android ui
Log.d( "mmmmmmmm"
,
"handler "
+ msg.what ) ;
}
}
}
} |
【Android 如何有效的解决内存泄漏的问题】最终完整的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | package rxnet.zyj.com.myapplication;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import java.lang. ref .WeakReference;
public
class
HandlerActivity extends AppCompatActivity {
private
final
static
int
MESSAGECODE = 1 ;
private
static
Handler handler ;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
findViewById( R.id.finish ).setOnClickListener( new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
finish();
}
});
//创建Handler
handler =
new
MyHandler(
this
) ;
//创建线程并且启动线程
new
Thread(
new
MyRunnable() ).start();
}
private
static
class
MyHandler extends Handler {
WeakReference<
HandlerActivity>
weakReference ;
public
MyHandler(HandlerActivity activity ){
weakReference
=
new
WeakReference<
HandlerActivity>
( activity) ;
}
@Override
public
void
handleMessage(Message msg) {
super.handleMessage(msg);
if
( weakReference. get () !=
null
){
&nbs |