使用LeakCanary分析并解决Android内存泄露
来源:互联网 发布:淘宝切片 编辑:程序博客网 时间:2024/05/21 06:40
使用LeakCanary分析并解决Android内存泄露
- 使用LeakCanary分析并解决Android内存泄露
- Andorid app查找内存泄露的一般步骤
- 一些常见的Android内存泄露分析和解决方案
LeakCanary是一款内存泄露分析工具,至于什么是内存泄露网上有很多帖子,这里就不废话了,改工具是在app里植入一个新进程的和一个新入口的工具组件,也就是说使用了leakcanary的app安装后会在桌面看到两个app入口,卸载其中一个另外一个也会被卸载,并且两个入口运行在不同的进程。而在leakcanary入口里可以看到主app里内存泄露的所有信息。这里要说一下,当主app发生内存后,需要一段时间才能在leakcanary里看到,而不是马上就有,因为hprof文件的导出和分析需要很长时间,直到在notifycation出现通知才在leakcanary里能看到细节信息,LeakCanary托管在github上:点击进入
Andorid app查找内存泄露的一般步骤
- 运行app,先用DDMS内存管理点击GC按钮触发GC或者在adb shell下使用dumpsys meminfo 来观察app是否有内存泄露的嫌疑,这里一定要在app上多操作然后不断的观察内存变化的情况,如果是一直增加的话就可以怀疑有内存泄露的情况,有了leakcanary此步骤可以说在某种程度下能忽略
- 在项目里加入leakcanary,如果用的是AndroidStudio的话在gradle里加入如下代码:
dependencies { testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'}
- 然后在自定义application并在manifest里申明:
public class TestMemApplication extends Application { @Override public void onCreate() { super.onCreate(); Logger.addLogAdapter(new AndroidLogAdapter()); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } LeakCanary.install(this); // Normal app init code... }}
- 不断的在app里操作,如果有内存泄露的地方会有提示,然后查看,Leakcanary集成以后会在你的app进程之外开启一个新进程,也就是说如果你安装了包含leakcanary的app会发现桌面多出了两个图标,其中之一就是leakcanary,另外一个就是你自己的app了,可以通过点击leakcanary的图标进去查看内存泄露的相关信息。
一些常见的Android内存泄露分析和解决方案
- 匿名内部runnable持有当前activity实力释放不了,造成内存泄露,这是我们为了省事经常写的代码。
public class Activity1 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_1); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100000); // 耗时运算 例如网络请求 // 拿到资源后更新UI } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); }}
通过打断点可以发现runnable内部this持有activity实例
当从此activity1里退出的时候,如果线程没有结束就会造成activity无法释放而出现内存泄露
正确的用法是
public class Activity2 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_2); new Thread(new MyRunnable()).start(); } static class MyRunnable implements Runnable { @Override public void run() { try { Thread.sleep(100000); // 耗时运算 例如网络请求 // 拿到资源后更新UI } catch (InterruptedException e) { e.printStackTrace(); } } }}
很明显使用static内部类就不再持有activity实例
但是如果线程里要更新UI需要外部的activity实例,可以使用weakref,这样内部类实例不能持有activity2实例,如果activity2退出释放了,mAct为空线程就不会做UI更新了
public class Activity2 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_2); new Thread(new MyRunnable(this)).start(); } private void refreshUI() { // 更新UI } static class MyRunnable implements Runnable { WeakReference<Activity2> mAct; public MyRunnable(Activity2 act) { mAct = new WeakReference<>(act); } @Override public void run() { try { Thread.sleep(100000); // 耗时运算 例如网络请求 // 拿到资源后更新UI Activity2 activity2 = mAct.get(); if (null != activity2) { activity2.refreshUI(); } } catch (InterruptedException e) { e.printStackTrace(); } } }}
- AsyncTask用法同1
public class Activity3 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_3); new MyAsyncTask(this).execute(); } static class MyAsyncTask extends AsyncTask<Void, Void, Void> { private WeakReference<Activity3> mAct; public MyAsyncTask(Activity3 act) { super(); mAct = new WeakReference(act); } @Override protected Void doInBackground(Void... params) { // 耗时操作 return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Activity3 activity3 = mAct.get(); if (null != activity3) { // 更新UI } } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); Activity3 activity3 = mAct.get(); if (null != activity3) { // 更新UI } } }}
- Handler用法同1
public class Activity4 extends AppCompatActivity { private Handler mHandler = new MyHandler(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_4); // 延迟发送 mHandler.sendEmptyMessageDelayed(0, 100000); } private void refreshUI() { } private static class MyHandler extends Handler { private WeakReference<Activity4> mAct; public MyHandler(Activity4 act) { mAct = new WeakReference<>(act); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: // 收到延迟10秒发送的消息0 然后更新UI Activity4 activity4 = mAct.get(); if (null != activity4) { // 更新UI activity4.refreshUI(); } break; default: break; } } }}
- IO相关的连接使用完后要释放
public class Activity5 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_5); new Thread(new MyRun(getApplicationContext())).start(); } private static class MyRun implements Runnable { private Context mCtx; public MyRun(Context ctx) { mCtx = ctx; } @Override public void run() { String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath(); String filePath = sdPath + File.separator + "test.txt"; File file = new File(filePath); Logger.i("file = " + filePath); if (!file.exists()) { return; } RefWatcher refWatcher = TestMemApplication.getRefWatcher(mCtx); FileInputStream in = null; BufferedInputStream bin = null; try { in = new FileInputStream(file); bin = new BufferedInputStream(in); refWatcher.watch(in); refWatcher.watch(bin); byte[] buffer = new byte[1024]; int len = -1; while ((len = bin.read(buffer)) != -1) { Logger.i(new String(buffer, len)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (null != bin) { try { bin.close(); } catch (IOException e) { e.printStackTrace(); } finally { if(null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } } } }}
集合里不用的item一定要删除,不然也会内存泄露
BroadcastReceiver和各种listener一定要在Activity里的onDestory里反注册
自定义的一些类需要context的时候不要直接用activity而使用activity.getApplicationContext()
各种adapter里要重用convertView,不然内存会被耗尽切无法回收
使用各种推送SDK用来更新UI的时候,在各个activity里注册的时候使用weakRef,防止泄露
- 使用LeakCanary分析并解决Android内存泄露
- android 内存泄露分析及调试(LeakCanary使用)
- Android内存泄露分析工具LeakCanary
- 使用leakcanary分析程序中的内存泄露
- Android 使用LeakCanary 检测内存泄露
- Android 使用LeakCanary 检测内存泄露
- Android 使用LeakCanary 检测内存泄露
- Android 使用LeakCanary 检测内存泄露
- 使用leakcanary检测Android项目内存泄露
- Android 内存泄露检测工具 LeakCanary
- Android内存泄露检测(LeakCanary)
- LeakCanary-Android内存泄露检测
- Android内存泄露自动检测LeakCanary
- android leakCanary检测内存泄露
- Android内存泄露自动检测LeakCanary
- Android LeakCanary 检测内存泄露
- 使用LeakCanary检测内存泄露
- 使用LeakCanary检测内存泄露
- mui利用javascript dom元素写的唯品会首页上拉加载更多
- POJ3678 Katu Puzzle【2-SAT】
- BZOJ1537: [POI2005]Aut-The Bus
- Android性能优化典范
- 服务器自动推送到客户端浏览器
- 使用LeakCanary分析并解决Android内存泄露
- 字符集和字符编码(Charset & Encoding)
- ImageScrollView的封装
- UE4 C++射线检测
- Source Insight崩溃的2种解决方法
- ubuntu 17.04 如何安装gnome桌面
- vue动态组件和slot插槽
- 每日一发Python---Python中shelve模块用法
- spring学习笔记 -- day12 ssh整合之基于XML的独立式整合