内存泄漏的原因及解决办法是什么

原因及解决方法为:1、使用静态内部类,避免线程造成的内存泄漏;2、使用缓存的convertView构造Adapter,避免使用ListView造成的内存泄漏;3、退出程序前,clear集合里的东西,置为null,避免集合容器中的内存泄露等。

原因及解决方法为:1、使用静态内部类,避免线程造成的内存泄漏;2、使用缓存的convertView构造Adapter,避免使用ListView造成的内存泄漏;3P q R p * 5、退出程序前– U # X e,clear集合里的东西,置为null,避免集合容器中的内存泄露等。

内存泄漏的原因及解决办法是什么

本教程操作环境:windows7系统、Dell G3电脑。

# $ t v ~见的内存泄露造成的原因

1、单例造成的内存泄漏

由于单例的静态特性使得其生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而单例对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。

示例:防止单例导致内存泄漏的实例

// 使用了单例模式
puG Q j ? Jblic claU & = +ss AppManager {
private static AppManager instance;
private Context contex? _ ; R ( } 8 At;
pQ w u @rivate AppManager(Context context)t \ V R p V k {
this.contb m 1ext = contex0 l 0 L * p W Rt;
}
public static AppManager getInstance(ContexT ! J 1 wt context) {
if (instance != null) {
instance = new AppManager(contexb h p X N # W T qt);
}
return instance;
}
}

2、非静态内部类创建静态实例造成的内存泄漏

例如,有时候我们可能会在启动频繁的Activity中,为了避免重复创建相同的数据资源,可能会出现如下写法:

  public class MainActivity extends AppCompatActivity {
private stal z C j H % #tic TestResou; W ? $ 3 e krce mRea } P j | r + |source = null;
@Override
protected void onCreate(Bundle savedI! [ 0 X _ /nstanceStat\ H U $ V 7e) {
super.onCreate(savedInstanceSt0 h _ate);
sk S Y u .etContentView(R.layout.activity_mL | f $ x Dain);
if(mResource == null){
mResource = new TestResource();
}
//...
}
class TestResource {
//...
}
}

3、Handler造成的内存泄漏

示例:创建匿名内部类的静态对象

public class MainActivity extends AppCompatActivity {
private fi\ ) t N ]nal Handler handler = new Handler() {
@Overrid/ 1 Oe
public voi] 2 @ .d handleMess\ m 8 D i s % page(Message msg) {
/D , t n $ $ M |/ ...
}
};
@Override
protected void o6 ( \ =nCreal x : ` f \te(Bundle savedInstanceState) {
sj % j % w [ 1ua w W 3per.onCreate(savedInstanceState);
setContent} s 9 _ Z TView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
publi7 r yc void run() {
// ...
handler.sendEmptyMessage(0x123q y # o t ! @ =);
}
});
}
}

1、从Android的角度

当Android应用程序启动时,该应用程序的主线程会自动创建一个Looper对象和与之关联的MessageQueue。当主线程中实例化一个Handc ) g M T c u e Cler对象后,它就会自动与主线程Loopf @ % n ?er的MessageQueue关联起来。所有发送到Me# : % ! essageQueue的Messag都会持有Handler的引用,所以Looper会据此n = 0 h ; h 1回调Handle的@ _ w I hhandleMessage()方法来处理消息。只要MessageQueue中有未处理的Message,Looper就会不断的从中取出并交给Handler处理。另外,主线程的L5 i 6 y M 7ooper对象会伴随该应用程序的整个生命周期。

2、 Java角度

在Java中,1 g p x ; j非静态内部类和匿名类内部类都Y ) + ) =会潜在持有它们所属的外部类的引用,但是静态内部类却不会。

对上述8 S O 3 w f [ _的示例进行分析,当MainAcZ $ 5tivity结束时,未处$ K 2理的消息持有handler的引用,而handl3 } ? oeq P m R i o o G Ur又持有它所属的外部类也就是MainActivity的引用。这条引用I , * w ~ ) B关系会一直保持直到消息得到处理,这样阻止了MainActivity被垃圾回收器回收,从而造成了内存泄漏。& A = i z

解决方法:将Handler类独立出来或者使用静态内部类,这样便可以避免内存泄漏。

4、线程造成的内存泄漏

示例:AsyncTask和Runnable

pub5 S \lic class MainActivity extends AppCompatActivity {{ t : _ 9 * u z l
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new MyRunnable()).staR V P n !rt();
new MyAsyncTasR M 3 3 Ak(this).Z L x { |execute();
}
class MG N XyA{ 1 W 5 /syncTaskh w # f 4 b 0 ~ extends A% w H t A a A ( ~syncTask<Void, Void, Void>U T 3 / 9; {
/* g m/ ...
public MyAsyncTask(Context context) {
// ...
}
@Override
protected Void doInBackground(Void... params) {
// ...
reZ v Oturn null;
}
@Override
protected void onPostExecute(Void aVoid) {
// ...
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
// ...
}
}
}

AsyncTask和Runnable都使用了匿名内部类,那么它们将持有其所在Activity的隐式引用。如果任务在Activity销毁之前还未完成,那么将导致Activity的内存资源无法被回收,从而造成内存泄漏。

解决^ m ? p L方法:将AsyncA ! ` f } \ j E wTa0 t s R 6 n d _sk和Runnable类独立出来或者使用静态内部类,这样+ ) C b F 0便可以避免内存泄漏。

5、资源未关闭造成的内存泄漏

对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,应该在Activity销毁时及时关闭或O M ] }者注销,否则A , C p这些资源将不会被回收,从而造成内存泄漏。

1)比如在Activity中register了一个BraodcastReceiver,但在Activity* ; k结束后没有unregister该BraM / . T *odcastReceiver。

2)资源性对象比如Cursor,Stream、File文件等往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们2 f \ 0 $ $ O .的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,k \ B q还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。

3)对于资源性对象在不使用的时候,应该调用它的close()函数将其关闭掉,然后再设置为null。在我们的程序退出时一定要确保我们的资源性对象已经关闭。

4)Bitmap对象不在使用时调用recycle()释放内存。2.3以后的bitmap应该是不需要手动recycle了,内存已经在java层了。

6、使用x g v t D ? g BListView时造成的内存泄漏

初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定d o u 9 h数量的View对象,同时ListView会将这些View对象缓存起来。当向上滚动ListView时,原先位于最上面的Item的% V K u k *View对象会被回收,然后被用来构造新出现在下面的Item。这个构造过程就是由getView()方法完成的,getView()的第二个形参convertView就是被缓存起来的Item的Viewo a l $ s对象(初始化时缓存中没有View对象则convertView是nk ( – # @ j Gull)。

构造Adapter时,没有使用缓存的convertView。

解决方法:在构造Adapter时,使用缓存的convertView。

7、集合容器中的内存泄露

我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。

解决s _ [方法:在退出程序之前,将集合里的东西clear,L 6 T然后置为null,再退出程序。

8、Webn s K UView造成的泄露

当我们不要使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其占用的内存,否则其长期占用的内存也x I I T 4 8 4 9 J不能被回收,从而造成内存泄露。

解决方法:为WebV\ i C }iew另外开\ O V s 0 s J ] 1启一个进程,通过AIDL与主线程进行通信,WebView所在的{ L % J进程可以根3 V { U ) lI o 4 s业务的需要选择合适的时? 6 g E + U J %机进行销毁,从而达到内存的完整释放。

更多计算机相关知识,请访问常见问题栏目u { f ? m O

以上就是内存泄漏的原因及解决办法是什么的详细内容,更多请关注php中文网其它相关文章!

php中文网最新课程二维码

声明:本文原创发布php中文网,转载请注明出处,感谢您的尊重!如有疑问,请联系admin@php.cn处理

原创文章,作者:町子门户,如若转载,请注明出处:https://www.6fzz.com/12135.html

(0)
上一篇 2021年5月17日 下午11:16
下一篇 2021年5月17日 下午11:16

相关推荐

发表评论

您的电子邮箱地址不会被公开。