吉恩聊城网站建设,网站广告做的好的企业案例分析,百度推广开户价格,高端网站建设找哪个公司Android中的内存泄漏#xff1a;
先说一下为什么会出现内存泄漏#xff1a;
Android程序开发中#xff0c;如果一个对象已经不需要被使用了#xff0c;本该被回收时#xff0c;而这时另一个对象还在持有对该对象的引用#xff0c;这样就会导致无法被GC回收#xff0c;…Android中的内存泄漏
先说一下为什么会出现内存泄漏
Android程序开发中如果一个对象已经不需要被使用了本该被回收时而这时另一个对象还在持有对该对象的引用这样就会导致无法被GC回收就会出现内存泄漏的情况。
内存泄漏时Android程序中出现OOM问题的主要原因之一。所以我们在编写代码时一定要细心处理好这一类的问题。
下面说一下Android开发中最常见的5个内存泄漏问题
一单例设计模式造成的内存泄漏
单例设计模式我就不多说了这个是最基本的设计模式相信大家都会使用但是时候我们在使用单例设计模式时没有注意到其中的细节就会造成内存泄漏。
单例设计模式的静态特性会使他的生命周期和应用程序的生命周期一样长这就说明了如果一个对象不在使用了而这时单例对象还在持有该对象的引用这时GC就会无法回收该对象造成了内存泄露的情况。 下面是错误的单例设计模式的代码
public class AppManager { private static AppManager instance; private Context context; private AppManager(Context context) { this.context context; } public static AppManager getInstance(Context context) { if (instance ! null) { instance new AppManager(context); } return instance; } } 上面的代码是一个最普通的单例模式但是需要注意两个问题 1、如果我们传入的Context是Application的Context的话就没有任何问题因为Application的Context生命周期和应用程序生命周期一样长。
2、如果我们传入的Context是Activity的Context的话这时如果我们因为需求销毁了该Activity的话Context也会随着Activity被销毁但是单例还在持有对该类对象的引用这时就会造成内存泄漏。
所以正确的单例模式写法应该是这样的
public class AppManager { private static AppManager instance; private Context context; private AppManager(Context context) { this.context context.getApplicationContext(); } public static AppManager getInstance(Context context) { if (instance ! null) { instance new AppManager(context); } return instance; } } 这样的话不管我们传入什么样的Context最终使用的都是Application的Context单例的生命周期和应用一样长这样就不会造成内存泄漏了。
二、非静态内部类创建的静态实例造成的内存泄漏
有时候因为需求我们会去频繁的启动一个Activity这时为了避免频繁的创建相同的数据源我们通常会做如下处理 public class MainActivity extends AppCompatActivity { private static TestResource mResource null; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(mManager null){ mManager new TestResource(); } //... } class TestResource { //... } } 这样就在Activity中创建了非静态内部类非静态内部类默认持有Activity类的引用但是他的生命周期还是和应用程序一样长所以当Activity销毁时静态内部类的对象引用不会被GC回收就会造成了内存溢出解决办法
1、将内部类改为静态内部类。
2、将这个内部类封装成一个单例Context使用Application的Context
三、Handler造成的内存泄漏
先看一下不规范的Handler写法
public class MainActivity extends AppCompatActivity { private Handler mHandler new Handler() { Override public void handleMessage(Message msg) { //... } }; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); loadData(); } private void loadData(){ //...request Message message Message.obtain(); mHandler.sendMessage(message); } } 这里的handler也是一个非静态匿名内部类他跟上面的一样也会持有Activity的引用我们知道handler是运行在一个Looper线程中的而Looper线程是轮询来处理消息队列中的消息的假设我们处理的消息有十条而当他执行到第6条的时候用户点击了back返回键销毁了当前的Activity这个时候消息还没有处理完handler还在持有Activity的引用这个时候就会导致无法被GC回收造成了内存泄漏。正确的做法是
public class MainActivity extends AppCompatActivity { //new一个自定义的Handler private MyHandler mHandler new MyHandler(this); private TextView mTextView ; //自定义静态内部类继承自Handler private static class MyHandler extends Handler { private WeakReferenceContext reference; //在构造函数中使用弱引用来引用context对象 public MyHandler(Context context) { reference new WeakReference(context); } Override public void handleMessage(Message msg) { MainActivity activity (MainActivity) reference.get(); if(activity ! null){ activity.mTextView.setText(); } } } Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView (TextView)findViewById(R.id.textview); loadData(); } private void loadData() { //...request Message message Message.obtain(); mHandler.sendMessage(message); } Override protected void onDestroy() { super.onDestroy(); //移除队列中所有的Runable和消息 //这里也可以使用mHandler.removeMessage和mHandler.removeCallBacks来移除指定的Message和Runable mHandler.removeCallbacksAndMessages(null); } }
创建一个静态内部类继承自handler然后再在构造参数中对handler持有的对象做弱引用这样在回收时就会回收了handler持有的对象这里还做了一处修改就是当我 们的回收了handler持有的对向即销毁了该Activity时这时如果handler中的还有未处理的消息我们就需要在OnDestry方法中移除消息队列中的消息。 四、线程造成的内存泄漏 线程使用不恰当造成的内存泄漏也是很常见的下面举两个例子 //——————test1 new AsyncTaskVoid, Void, Void() { Override protected Void doInBackground(Void... params) { SystemClock.sleep(10000); return null; } }.execute(); //——————test2 new Thread(new Runnable() { Override public void run() { SystemClock.sleep(10000); } }).start(); 上面是两个内部类当我们的Activity销毁时这两个任务没有执行完毕就会使Activity的内存资源无法被回收造成了内存泄漏。 正确的做法是使用静态内部类如下 static class MyAsyncTask extends AsyncTaskVoid, Void, Void { private WeakReferenceContext weakReference; public MyAsyncTask(Context context) { weakReference new WeakReference(context); } Override protected Void doInBackground(Void... params) { SystemClock.sleep(10000); return null; } Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); MainActivity activity (MainActivity) weakReference.get(); if (activity ! null) { //... } } } static class MyRunnable implements Runnable{ Override public void run() { SystemClock.sleep(10000); } } //—————— new Thread(new MyRunnable()).start(); new MyAsyncTask(this).execute(); 这样就避免了内存泄漏当然在Activity销毁时也要记得在OnDestry中调用AsyncTask.cancal()方法来取消相应的任务。避免在后台运行浪费资源。
五、资源未关闭造成的内存泄漏 在使用完BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源时一定要在Activity中的OnDestry中及时的关闭、注销或者释放内存 否则这些资源不会被GC回收就会造成内存泄漏。 --------------------- 原文https://blog.csdn.net/qq_35373333/article/details/74909811