内存泄漏 快速过一下

java 内存泄漏 基础知识

java 内存的分配策略

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

  • 静态存储区,也叫方法区,这个内存区里 主要存放一些 静态数据,全局变量等等,这块内存,程序编译的时候已经分配好了,并且在静态存储区中存储的变量,在整个程序运行期间 都存在
  • 栈区 ,方法执行的时候,方法体内的局部变量,会在栈上创建内存空间,并在方法执行结束之后,这些变量所持有的内存会被自动释放,因为栈内存分配运算,内置于处理器中,所以效率很高,但是栈区的内存空间 容量有限
  • 堆区,又称为动态内存分配,通常就是我们 new 对象出来的内存,这部分内存在不使用的时候,会被 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 内存管理机制

  • 分配机制
    安卓 在为每一个进程分配内存的时候,采用了一个弹性的分配方式,也就是说:系统一开始,不会为这个APP分配太多的内存,而是为每一个APP进程分配一个小额的量,而这个小额的量是根据每一个移动设备的物理RAM尺寸大小决定的,随着App的不断运行,当前内存不足,android 就会继续为 app 分配更多的内存,当然是有限的。总之,android系统的内存分配机制,就是让更多的进程存活在内存中,当用户下一次启动该APP进程时候,就不需要重新创建进程,而是恢复已有的进程就可以了,提高了体验。

  • 回收机制
    android对内存的使用,是尽最大限度地使用,这是继承Linux 的特点。
    当系统发现内存不足的时候,就会杀死其他进程。为新进程分配内存
    所以就有个优先级
    前台进程
    可见进程
    服务进程 :会开启一些服务
    前三个不会被杀死
    后台进程:存放在一个缓存列表中,数据结构是LRU,先杀死的处于列表的尾部
    空进程 :为了平衡系统的性能,Android不会保存这些进程。

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

内存管理的目标

  • 更少的占用内存
  • 在合适的时候,合理的释放系统资源
  • 在合理的生命周期中,保存或者还原重要的数据

内存优化的方法

  • service 完成任务后,尽量停止它。因为他是优先级比较低的服务进程,影响内存回收, 用IntentService 替代 service,因为IntentService 继承service内部开启子线程,可以做耗时操作,还可以自动退出。而不是像Service 要手动 stopService。

  • 在Ui 不可见的时候,释放掉一些只有Ui使用的资源,有个 OnTreeMemory() 通知App回收资源

  • 内存紧张的时候,也是用OnTreeMemory() 通知App回收资源

  • Bitmap 导致的,根据当前设备的分辨率来压缩bitmap,使用bitmap之后 使用recycle() 释放c内存,使用软引用,使用LRU。

  • 使用针对内存优化过的数据结构,替代hashmap 的 SparseArray、ArrayMap,同时,尽量少用 枚举,消耗的内存是常量的两倍

  • 避免使用依赖注入框架,使用這些框架 除了方便,也会带来一些扫描注解带来的系统资源

  • 使用ZIP 对齐的APK

  • 使用多进程,定位,push,webView。当然多进程 的安全,数据传输 很难的问题

内存溢出 VS 内存泄漏

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容