Android常见内存泄漏和LeakCanary的使用
2017-01-08 23:49
363 查看
App有内存泄漏就是埋了一颗定时炸弹, 累积多了终将导致OOM. 下面列举一些常见导致内存泄漏的代码.
写Util的时需要Context的时候, 判断一下, 如果可以用ApplicationContext优先使用.
可以用ApplicationContext的情况下在Application里面加上一个getInstance()方法, 就不用传Context进来了.
Application配置
AndroidManifest.xml
未注销导致的内存泄漏
使用了广播, EventBus等等, 会导致Activity无法被GC回收@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); EventBus.getDefault().register(this); } @Subscribe public void onEvent(MessageEvent msg) { } @Override protected void onDestroy() { super.onDestroy(); //未移除注册的EventBus // EventBus.getDefault().unregister(this); }
非静态内部类使用不当导致的内存泄漏
非静态内部类会持有外部类引用, 如果Activity中包含了静态的内部类成员就会导致内存泄漏private static InnerClass mInnerClass; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); mInnerClass = new InnerClass(); } //非静态内部类持有外部类引用 public class InnerClass { private String msg; public InnerClass() { } }
匿名类使用不当导致的内存泄漏
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); //匿名类持有外部类引用 new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } }.execute(); }
工具类使用不当导致的内存泄漏
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); String s = Util.getInstance(this).doSomething(); }
public class Util { private volatile static Util instance; private static Context mContext; private Util(Context context) { mContext = context; } //传进来的context被静态持有 public static Util getInstance(Context context) { if (instance == null) { synchronized (Util.class) { if (instance == null) { instance = new Util(context); } } } return instance; } public static String doSomething() { String string = mContext.getResources().getString(R.string.app_name); return string; } }
写Util的时需要Context的时候, 判断一下, 如果可以用ApplicationContext优先使用.
可以用ApplicationContext的情况下在Application里面加上一个getInstance()方法, 就不用传Context进来了.
public class App extends Application { private static App instance; public static App getInstance() { return instance; } @Override public void onCreate() { super.onCreate(); instance = this; } }
线程使用不当导致的内存泄漏
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); //Activity实例被Runnable持有, Runnable传入l一个异步线程, // 此线程和此Acitivity生命周期不一致的时候,就造成了Activity的泄露。 new Thread(new Runnable() { @Override public void run() { while (true) ; } }).start(); }
Handle使用不当导致的内存泄漏
private Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); //Handler 为非静态内部类,它会持有外部类的引用 mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { //doSomething } }, 1000 * 20); }
静态集合使用不当导致的内存泄漏
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); ActivityCollector.addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); //静态集合没有移除元素 // ActivityCollector.removeActivity(this); }
public class ActivityCollector { public static List<Activity> activities = new ArrayList<Activity>(); public static void addActivity(Activity activity) { activities.add(activity); } public static void removeActivity(Activity activity) { activities.remove(activity); } }
使用弱引用避免内存泄漏
在 Activity 中避免使用非静态内部类,比如上面我们将 Handler 声明为静态的,则其存活期跟 Activity 的生命周期就无关了。同时通过弱引用的方式引入 Activity,避免直接将 Activity 作为 context 传进去public class WeakReferenceActivity extends AppCompatActivity { //将 Handler 声明为静态 没有了Activity的引用, 无法直接引用其变量或方法, // 使用弱引用WeakReference来解决这个问题 private static class DBHandler extends Handler { //弱引用, 而不是使用外部类this或者传进来 private final WeakReference<WeakReferenceActivity> mActivity; public DBHandler(WeakReferenceActivity activity) { mActivity = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { WeakReferenceActivity activity = mActivity.get(); if (activity != null) { Toast.makeText(activity, "what: " + msg.what, Toast.LENGTH_SHORT).show(); } } } private final DBHandler mHandler = new DBHandler(this); private static final Runnable sRunnable = new Runnable() { @Override public void run() { Toast.makeText(App.getInstance(), "sRunnable run()", Toast.LENGTH_SHORT).show(); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weak_reference); mHandler.postDelayed(sRunnable, 1000 * 20); } public void onClick(View view) { mHandler.sendEmptyMessage(new Random().nextInt(10)); } }
LeakCanary的使用
build.gradle dependencies{…}添加//https://github.com/square/leakcanary debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
Application配置
public class App extends Application { private static App instance; private static RefWatcher sRefWatcher; public static RefWatcher getRefWatcher() { return sRefWatcher; } public static App getInstance() { return instance; } @Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } sRefWatcher = LeakCanary.install(this); // Normal app init code... instance = this; } }
AndroidManifest.xml
<application android:name="yourApp" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> </application>
检测Fragment内存泄漏
public class LeakFragment extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_common, container, false); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); new Thread(new Runnable() { @Override public void run() { while (true) ; } }).start(); } @Override public void onDestroy() { super.onDestroy(); //onDestroy中添加 App.getRefWatcher().watch(this); } }
相关文章推荐
- android之内存泄漏检测和解决方法及LeakCanary使用
- LeakCanary (Android 检测内存泄漏工具的使用)
- Android的内存机制和常见泄漏情形
- Android 使用LeakCanary 检测内存泄露
- Android检测内存泄漏之leakcanary
- Android 内存泄漏分析利器——leakcanary
- 【Android程序优化,避免内存泄露】- [实战一]:避免内存泄露的最后一道墙,使用leakcanary分析程序中的内存泄露。
- 在android上使用valgrind检测内存泄漏
- 【Android程序优化,避免内存泄露】- [实战一]:避免内存泄露的最后一道墙,使用leakcanary分析程序中的内存泄露。
- Android减少内存泄漏之静态内部类的使用
- Android 常见的内存使用不当的情况
- Android性能优化之内存泄漏分析工具LeakCanary
- android内存泄露检测工具--LeakCanary 中文使用说明
- Android 使用LeakCanary 检测内存泄露
- Android Context 使用时注意内存泄漏问题
- Android 使用LeakCanary 检测内存泄露
- Android 常见内存泄漏之四大元凶
- Android性能优化之常见的内存泄漏
- Android 内存分析 与泄漏 和 MAT 使用
- 利用 LeakCanary 来检查 Android 内存泄漏