当前位置:首页 > 活动评测

Android内存泄漏如何避免

admin 2025-10-29 05:46:31 6766

内存泄漏如何避免

1. 内存泄漏2. 具体场景和避免办法2.1 单例模式2.2 非静态内部类2.2.1 内部类/匿名内部类2.2.2 Handler2.2.3 AsyncTask

2.3 集合/静态集合2.4 静态变量2.5 资源未释放

参考材料

1. 内存泄漏

是指程序中动态分配的堆内存由于某种原因没有及时回收,造成系统内存的浪费,导致程序运行变慢甚至是崩溃的结果。

根本原因: 一个生命周期较长的对象,强引用持有了一个生命周期较短的对象,导致短生命周期的对象在应该被销毁的时候没有被销毁。

2. 具体场景和避免办法

2.1 单例模式

项目中经常会用到一堆的工具类,有些工具类基本上就是全局单例的模式,而且它们在使用的时候又会经常的需要用到Context这个上下文变量,当传入这个变量的时候,这些工具类就会持有对应Activity的强引用了。

public class SingleInstance {

//像这样的单例工具类,调用的时候都是直接使用instance变量

//要更新的时候就会调用newInstance

private static SingleInstance instance;

private Context mContext;

private SingleInstance(Context context){

mContext = context;

}

private static SingleInstance getInstance(Context context){

if (instance == null)

return new SingleInstance(context);

return instance;

}

}

public class MainActivity extends AppCompatActivity {

private static MainActivity instance;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

instance = this;

}

}

这种情况下Activity退出后,由于这些单例还持有Activity的强引用,所以导致分配给Activity的堆内存就没法回收,这就造成了内存泄漏。

避免办法:

一些生命周期比较短的对象,不要作为成员变量传入,也不要被任何长期对象持有。用弱引用代替强引用,这样不会阻拦GC回收对象。

public class SingleInstance {

//像这样的单例工具类,调用的时候都是直接使用instance变量

//要更新的时候就会调用newInstance

private static SingleInstance instance;

private Context mContext;

private SingleInstance(){}

private fun(Context context) {

// 处理逻辑

}

private static SingleInstance getInstance(){

if (instance == null)

return new SingleInstance();

return instance;

}

}

```java

public class MainActivity extends AppCompatActivity {

private static WeakReference instance;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

instance = new WeakReference<>(this);

}

}

2.2 非静态内部类

在Java中,非静态内部类会隐形持有外部类的引用,而且是强引用。

2.2.1 内部类/匿名内部类

有时候经常会需要临时new一个Thread出来工作的情况,这种时候这个临时工线程就会拥有Activity的引用了,这种情况下如果Activity退出销毁后,也不会回收内存,这就又造成内存泄漏了。

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new Thread(new Runnable() {

@Override

public void run() {

try {

//假装在做耗时的工作

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

}

2.2.2 Handler

还有Handler的内部类使用,我们经常也是这么用的,这个就更夸张了,Android Studio就直接报警告提醒你会内存泄漏了。 Handler的生存周期并不会因为你是写在Activity里面就和Activity一样,所以会造成内存泄漏。

2.2.3 AsyncTask

这个也是会不经意间就直接写成Activity内部类的类型,也会持有Activity的强引用。

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new MyasyncTask().execute();

}

static class MyAscnyTask extends AsyncTask{

@Override

protected Void doInBackground(Void... params) {

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return null;

}

}

避免办法:

还是和之前一样,改用弱引用来代替强引用。使用静态变量,这样就无法持有外部类的引用了。

2.3 集合/静态集合

在开发过程中经常会有用到集合的时候,集合内的元素会随着添加而越来越多,如果是静态集合那么生命周期会和应用程序一样长,这样就非常占内存。

static List objectList = new ArrayList<>();

for (int i = 0; i < 10; i++) {

Object obj = new Object();

objectList.add(obj);

obj = null;

}

避免办法:用不到的集合元素要及时的清理。

2.4 静态变量

静态变量本身的生命周期就和应用程序一样长,不当的使用自然会造成内存泄漏。 避免办法:正确的使用静态变量…之前说的集合那些就避免用静态变量就行了,不得不用的时候就记得清理。

2.5 资源未释放

在开发过程中,经常会有应该及时关闭/释放的对象却没有记得这么做,这里就列举一下有哪些

Service:bindService()忘记unbindService()。BroadcastReceiver:registerReceiver()后忘记unregisterReceiver()。文件流,SQLite等需要关闭的对象:open()之后忘记close()。加载的图片资源Bitmap:这个是图片,占内存比较多,不用的时候一定要记得关闭,调用recycle()方法。

参考材料

Android 关于内存泄露,你必须了解的东西 - 简书 https://www.jianshu.com/p/65f914e6a2f8 一篇技术好文之Android性能优化内存泄漏无处可藏(图文) - 简书 https://www.jianshu.com/p/86a6d5cd3b05