Android 内存泄漏和内存溢出总结

一、导致内存泄漏的原因有哪些?

内存泄漏的根本原因是:长生命周期的对象持有短生命周期的对象,短生命周期的对象就无法及时释放。

造成内存泄漏的原因有:

(1) 单例造成的内存泄漏

因为某些单例的初始化需要引入一个Context变量,在调用单例时会传入当前类的实例,而单例的对象是静态的,那么它将与Application拥有一样长的生命周期,如果当前类需要销毁,由于单例持有该类的引用,所以无法销毁,从而造成内存泄漏,代码如下:

public class Singleton{ 
  private Singleton(Context context){ 
  } 
  private static volatile Singleton instance = null; 

  public static Singleton getInstance(Context context){ 
    if(instance==null){ 
        synchronized(Singleton.class){ 
          if(instance==null){ 
          instance = new Singleton(context); 
          } 
      } 
  } 
return instance; 
} 
}

解决方法:使用getApplicationContext或者对Activity的引用使用弱引用。

(2)非静态内部类实例化一个静态的对象

非静态内部类隐性持有外部类的对象,如果将内部类实例化为一个静态对象,那么它将与Application拥有一样长的生命周期,如果外部类需要销毁,由于内部类持有该类的引用,所以无法销毁,从而造成内存泄漏,代码示例如下:

public class MyActivity extends Activity{
    private static InnerClass innerclass = new InnerClass();
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(saveInstanceState);
        
    }
    private class InnerClass{
    }
}

(3) Handler/Runnable造成的内存泄漏

Handler是一个非静态内部类,它隐性地持有外部类的对象。如果外部类需要结束,但消息队列中还有消息未处理完,则Handler不会释放外部类的对象,从而造成内存泄漏,代码示例如下:

Handler handler = new Handler(){
    public void handleMessage(Message msg){
        super.handleMessage(msg);
    }
};

解决方法:
1.将Handler/Runnable改为静态的,如果是Handler,则在onDestroy中调用removeCallbackAndMessage(null)方法。
2. 如果Handler/Runnable持有外部类的对象,则应该改成弱引用。

(4)资源未关闭造成的内存泄漏

如使用流资源,比如InputStream,Database等,还有就是BroadcastReceiver未取消注册等。

二、导致内存溢出的原因有哪些?

内存溢出通俗理解就是内存不够用,内存溢出有以下几种原因:

1.从Java虚拟机角度来说

  • Java堆溢出
    Java堆用于存储对象实例的。只要不停创建对象,然后保证对象到GC Roots之间有可达路径来避免垃圾回收机制回收这些对象,那么对象数量达到最大堆容量后就会出现内存溢出,所以内存泄漏可能造成内存溢出。

  • 虚拟机栈和本地方法栈溢出
    如果线程请求的栈深度大于虚拟机所允许的最大深度,则抛出StackOverflowError异常;如果虚拟机在扩展时无法请求到足够的内存空间,则抛出OutOfMemoryError异常。

  • 方法区和运行时常量池溢出
    这类溢出经常出现在使用的第三方软件中的BUG。

  • 本地直接内存溢出

  1. 从App实际应用来说
  • 图片造成内存溢出
  • 内存泄漏导致的内存溢出
  • ListView未复用ConvertView导致重复创建Item布局最终可能导致内存溢出

三、如何避免OOM?

  1. Bitmap优化
  • 压缩图片尺寸,避免使用大图片
  • 设置合适的format,ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差异
  1. 使用StringBuilder替代String
    有时候代码中会需要使用到大量的字符串拼接操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。

  2. 可以复用系统自带的资源,如字符串、图片、颜色、样式等;ListView和GridView中可以使用ConvertView复用子组件。

  3. 避免内存泄漏从而避免内存溢出
    因为内存泄漏也可能导致内存溢出。

  4. 避免在类似onDraw这样的方法中创建对象,因为它会迅速占用大量内存,引起频繁的GC,甚至内存抖动。

参考:It一zhai男
原文:https://blog.csdn.net/u013293125/article/details/93593039

你可能感兴趣的:(Android 内存泄漏和内存溢出总结)