当前位置:   article > 正文

(原创)内存泄漏分析解决方案(一):内存泄漏的几种情况解决方式_android内存泄漏 android.os.process.killprocess(android

android内存泄漏 android.os.process.killprocess(android.os.process.mypid())

Android开发,内存优化是一个很重要的问题,今天就对这方面的问题,做一个较为详细的介绍

在讲内存优化之前,先要将内存环境问题说清楚

java中内存环境分为三种

栈:用于存放基本数据类型和对象的引用

堆:用于存放创建出来的对象或者数组,由GC管理,被所有线程共享

方法区:也叫静态区,包含了静态变量和class对象,被所有线程共享

内存泄漏的原因,具体可以分为下面两种情况

1,当一个对象已经不需要使用时,准备被回收时,被另外一个对象持有了引用导致无法回收

2,有些对象只有有限的生命周期,在生命周期本该结束时,仍被引用。

内存泄漏的累积,会导致内存溢出。即OOM

接下来讲几种常见的内存泄漏情况和处理方法:

1,单例导致的内存泄漏

先来看以下代码,是一个简单的单例模式

  1. public class SingerDemo {
  2. private Context context;
  3. private static SingerDemo instance;
  4. private SingerDemo(Context context) {
  5. this.context = context;
  6. }
  7. public static SingerDemo getInstance(Context context) {
  8. if (instance == null) {
  9. instance = new SingerDemo(context);
  10. }
  11. return instance;
  12. }
  13. }

在单例的构造方法里面,会传入一个Context对象

如果我们传入的是Activity的Context,在Activity关闭时,这个单例的对象仍然持有Activity的引用

从而导致内存泄漏

这个解决的方法,就是在单例的构造方法里面做处理

使用getApplicationContext()获取到应用的Context

具体代码如下

  1. private SingerDemo(Context context) {
  2. // this.context = context;
  3. this.context = context.getApplicationContext();
  4. }

这个例子也告诉我们,在使用Context的时候,要注意区分情况。

2,非静态内部类创建静态实例导致的内存泄漏

再来看下面的代码

  1. public class MainActivity extends AppCompatActivity {
  2. private static MainClass mainClass = null;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. if (mainClass == null) {
  8. mainClass = new MainClass();
  9. }
  10. }
  11. private class MainClass {
  12. }
  13. }

这种情况下,非静态的内部类MainClass默认持有了MainActivity的引用

从而导致他的静态实例对象一直持有Activity的引用

在Activity关闭时无法释放

从而导致MainClass无法被内存回收,导致内存泄漏

解决方法

把内部类改成静态内部类即可

3,handler造成的内存泄漏

Handler的生命周期和Activity的生命周期是不一致的,

所以Activity关闭的时候

Handler可能还存在内存

看下面这个例子

  1. public class MainActivity extends AppCompatActivity {
  2. private final Handler myhandler = new Handler(Context context) {
  3. @Override
  4. public void handleMessage(Message msg) {
  5. super.handleMessage(msg);
  6. }
  7. };
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. myhandler.postDelayed(new Runnable() {
  13. @Override
  14. public void run() {
  15. }
  16. }, 1000 * 60 * 10);
  17. }
  18. }

当Handler延迟执行消息的时候,把Activity关闭

这个时候Handler持有了Activity的对象

导致了内存泄漏

解决的方法有两种,第一种

就是在Activity关闭时,remove掉Handler的消息

removeMessages:移除单个message

removeCallbacksAndMessages:移除全部message和回调

另外一种办法

1,将handler声明为静态的

2,通过弱引用的方式引入Activity,

对相关方法和View进行操作

代码如下:

  1. private static class MyHandler extends Handler {
  2. private WeakReference<MainActivity> mWeakReference;
  3. public MyHandler(MainActivity activity) {
  4. mWeakReference = new WeakReference<>(activity);
  5. }
  6. @Override
  7. public void handleMessage(Message msg) {
  8. super.handleMessage(msg);
  9. MainActivity mainActivity = mWeakReference.get();
  10. switch (msg.what) {
  11. case 0x001:
  12. if (mainActivity != null) {
  13. mainActivity.mTextView.setText(msg.obj + "");
  14. }
  15. break;
  16. default:
  17. break;
  18. }
  19. }
  20. }

4,线程导致的内存泄漏

线程导致的内存泄漏,处理方式和Handler一样

将Thread和Runnable

都声明为静态的

用弱引用的方式获得Activity对象

或者在合适的生命周期,

去结束这个线程

5,Webview造成的内存泄漏

Webview造成内存泄漏的原因有很多种

有时候需要移动端和网页端对应处理

这里提供一种解决方法

1,将Webview所处的Activity放在一个单独的进程当中

在Activity的配置清单里添加android:process=""属性即可

process属性的值即是你的进程的名字

2,关闭Activity时,调用下面这个方法,去杀掉这个进程即可

android.os.Process.killProcess(android.os.Process.myPid());

更多解决方式,可以参考这篇文章

WebView内存泄漏--解决方法小结

最后分享几个关于内存优化的点

1,频繁的字符串拼接使用StringBuilder代替String

2,ArrayMap,Sparse代替HashMap

3,不要频繁地创建和回收大量对象,避免内存抖动

因为在调用GC的过程中,会停住其他进程

一旦要处理的对象过多,就会造成UI卡顿等问题

4,复用系统自带的资源,ListView的item复用等

5,避免在onDraw方法里创建对象

6,及时关闭Cursor对象

7,注册和取消注册要成对出现。如广播的注册和取消注册

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/240281
推荐阅读
相关标签
  

闽ICP备14008679号