内存泄漏 快速过一下

2017-09-28  本文已影响18人  刘尔泽

java 内存泄漏 基础知识

java 内存的分配策略

静态分配, 栈式分配,堆式分配
对应的

栈区,跟堆区 :
栈区:在方法 体内定义的基本类型的变量,和对象的引用变量都是在方法的栈内存中分配的,当一段方法中定义变量时,java就会在栈中为该变量分配内存空间,当超过这个变量的作用域时,这变量就无效了,分配给它的内存空间就被释放,这时候栈区以前占着的内存空间就会被其他方法所使用。
堆区:存放所有 由new 创建的对象,以及数组,在堆中分配的内存,将由java 的垃圾回收器来管理,其中产生的一个数组,或者对象,还可以在栈中定义一个特殊的变量,也就是通过引用变量访问堆中的东西。

java是如何管理内存的

java 内存管理,就是对象的分配和释放问题, 通过 new 为对象申请内存空间,所有的对象都是在堆中分配的,gc 自动释放。简化了程序员的工作,但是加重了java虚拟的工作,这也是java 为啥慢的原因之一。 gc 是有很大作用的,为了正确的释放对象,他必须监控每一个对象的运行状态,包括,对象的申请,引用,被引用,复制等等。
可以把对象考虑为有向图的顶点,将引用关系考虑为有向图的边,从进程顶点开始的一颗有向根树,在有向图中,根顶点可达的对象 都是有效对象,根顶点不可达的对象是可以回收的对象。

java 中的内存泄漏

内存泄漏是指无用对象 持续占有内存,或者 无用对象的内存得不到及时的释放,从而造成的内存空间的浪费称为内存泄漏

Android 中的内存泄漏

单例
不恰当的使用单例,会导致内存泄漏

  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;
//    }
//    修复内存泄漏的写法:
private static AppManager instance;
private Context context;

private AppManager(Context context) {
    this.context = context.getApplicationContext();// 使用Application 的context
}

public static AppManager getInstance(Context context) {
    if (instance == null) {
        instance = new AppManager(context);
    }
    return instance;
  }
}

匿名内部类
非静态内部类默认会持有外部类的引用,应该设为 静态内部类

handler
handler 是非静态内部类。
解决:把handler 设为静态内部类,同时 在handler 的内部持有activity 外部类的弱引用。

//容易造成内存泄漏的写法:

//    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);
 //    }
  //
  //    static class TestResource {
  //        private static final String TAG = "";
//        //...
//    }

// 修复内存泄漏的方法:

 ★import java.lang.ref.WeakReference;
private MyHandler mHandler = new MyHandler(this);
private TextView mTextView ;
private static class MyHandler extends Handler {
    private WeakReference<Context> reference;
    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);
    loadData();
}

private void loadData() {
    //...request
    Message message = Message.obtain();
    mHandler.sendMessage(message);
}

@Override
protected void onDestroy() {
    super.onDestroy();
     mHandler.removeCallbacksAndMessages(null);
 }
 }

避免使用 static 成员变量

如果把成员变量声明为static,那么他的生命周期,和整个App的 生命周期是一致的,如果App进程 设计上是常驻内存的,那即使App 切到后台,这部分的static 变量也是不会被释放的,按照我们现在App内存管理机制,占内存较大的后台进程,将优先被回收,所以说当你的进程被回收了之后,你所存的那些变量,那些数据是不安全的。
所以这类问题,在类设计的时候要考虑好,是不是要在初始化的时候去设为静态成员,是不是可以考虑懒加载。如果一定要使用,一定要对这些变量的生命周期做一个管理。

资源未关闭造成的内存泄漏
使用广播啊,contenProvider ,文档啊,游标,socket,Bitmap,在 生命周期销毁的时候,关闭和注销这些资源

AsyncTask 造成的内存泄漏
跟 handler 一样,需要在 声明周期销毁的时候,cancle

Bitmap c 端的内存,需要 recycle()

内存管理机制

从操作系统的角度来说,内存就是一块数据存储区域,而且属于被操作系统调度的资源。
分配内存:操作系统会为每一个进程分配一个合理的内存大小,从而保证每一个进程正常使用。
回收机制:操作系统里的内存回收机制,在内存不足的时候会有一个合理的回收再分配的作用。

Android 内存管理机制

还有个回收效益的概念,当Android系统开始杀死进程的时候,系统会判断每一个进程杀死后带来的回收效益,因为android总是倾向于 回收更多的内存,当然杀死的越少越好。

内存管理的目标

内存优化的方法

内存溢出 VS 内存泄漏

内存溢出,其实就是OOM, 还是bitmap ,比如未压缩的bitmap。压缩啊,使用bitmap的属性,裁剪啊,回收啊。
内存泄漏, 就是本该被垃圾回收器 gc 的内存没有被回收。dump 分析 扯一下子。

上一篇下一篇

猜你喜欢

热点阅读