内存泄漏的定义
进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到gc roots导致无法被GC回收。无用的对象占据着内存空间,使得实际可使用内存变小,形象地说法就是内存泄漏了。Activity对象持有其View层以及所有相关的资源,因此Activity内存泄漏会使内存变小许多。
内存泄漏的几种情况及解决方法
- 单例模式下传入当前Activity的context,单例一直持有Activity的context直到单例生命周期结束,Activity退出也不会被回收。
public class SingleInstanceClass {
private static SingleInstanceClass instance;
private Context mContext;
private SingleInstanceClass(Context context){
this.mContext= context.getApplicationContext();
}
public static SingleInstanceClass getInstance(Context context){
if(instance==null){
instance = new SingleInstanceClass(context);
}
return instance;
}
@Override
public String toString() {
return "SingleInstanceClass{" +
"mContext=" + mContext +
'}';
}
}
解决方法:用getApplicationContext代替当前Activity的context。
- 采用了非静态的内部类,由于非静态的内部类的对象隐含保存了一个引用,指向它的外部对象,因此在回收时无法回收外部类。销毁重建后并没有被回收,会存在两个实例。
public class InnerClassMemoryLeak extends AppCompatActivity {
private static final String TAG = "InnerClassMemoryLeak";
private TextView view;
static Demo mDemo;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new TextView(InnerClassMemoryLeak.this);
view.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
view.setText("启动一个持有本对象的线程");
view.setTextSize(40);
view.setTextColor(Color.parseColor("#0000ff"));
setContentView(view);
mDemo = new Demo();
mDemo.run();
}
class Demo{
void run(){
Log.i(TAG, "run: ");
}
}
}
-
线程引起内存泄漏 启动线程的匿名内部类会隐式持有外部Activity的引用,当线程仍在运行而外部的Activity已经被销毁时会造成内存泄漏。 解决方法:尽量不使用匿名内部类,将内部类改为静态内部类,并使用弱引用WeakReference来保存Activity实例。
public class ThreadMomeryLeak extends AppCompatActivity {
private static final String TAG = "ThreadMomeryLeak";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_momery_leak);
new Mythread().start();
}
private static class Mythread extends Thread{
@Override
public void run() {
super.run();
try {
while(true){
Log.i(TAG, "running...");
Thread.sleep(1000L);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
-
Handler引起的内存泄漏,若MessageQueue中一个Message长时间未被取出,Message有Handler的引用,Handler有Activity的引用,若Activity退出时Handler还有Message需要处理,那么Activity不会被回收。 解决方法:弱引用Activity,将Handler设置为静态内部类。
public class HandlerMemoryLeak extends AppCompatActivity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_memory_leak);
mHandler=new MyHandler(this);
mHandler.sendEmptyMessage(0);
}
static class MyHandler extends Handler{
private WeakReference<HandlerMemoryLeak> mActivityRef;
public MyHandler(HandlerMemoryLeak activity){
mActivityRef = new WeakReference<HandlerMemoryLeak>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerMemoryLeak mla = mActivityRef == null ? null : mActivityRef.get();
if(mla == null || mla.isFinishing()){
return;
}
}
}
-
资源未及时关闭 解决方法:及时在onDestroy中close();
|