SHUI知道

这篇文章对Android性能优化篇之内存优化--内存泄漏总结得很到位,基本上涵盖了。感谢感谢。

什么是内存泄漏

当一个对象已经不需要在使用了,本应该被回收,而另一个正在使用的对象持有它的引用,导致对象不能被回收。因为不能被及时回收的本该被回收的内存,就产生了内存泄漏。如果内存泄漏太多会导致程序没有办法申请内存,最后出现内存溢出的错误。

android中导致内存泄漏的主要几个点

android开发中经常出现的点,我有只有了解了,才能更好的避免。

  1. 使用单例模式
  2. 使用匿名内部类
  3. 使用异步事件处理机制Handler
  4. 使用静态变量
  5. 资源未关闭
  6. 设置监听未取消
  7. 使用AsyncTask
  8. 使用Bitmap

上面就是我列出的几个常出现内存泄漏的几个点,下面我们将一一解读。

java虚拟机内存管理

java虚拟机内存分为虚拟机栈,本地方法栈,程序计数器,堆,方法区这几个模块,下面我们就来分析下各个模块。

一、虚拟机栈

  • 虚拟机栈主要的作用就是为执行java方法服务的,是Java方法执行的动态内存模型。
  • 会导致栈内存溢出(StackOverFlowError)

二、本地方法栈

为执行native方法服务的,其他和虚拟机栈一样

三、程序计数器

  • 是当前线程执行的字节码行号指示器
  • 处于线程独占区
  • 如果是执行的是java代码,当前值为字节码指令的地址,如果是Native,值为undefined

四、堆

  • 存放对象的实例
  • 垃圾收集器管理的主要区域
  • 分代管理对象
  • 会导致内存溢出(OutOfMemoryError)

五、方法区

  • 存放虚拟机加载的类信息,常量,静态变量,编译后的代码和数据
  • GC主要对方法区进行常量回收和类卸载
  • 会出现内存溢出(OutOfMemoryError)

java内存几种分配策略?

可以结合上面的内存分配模型,能很好的理解。

一、.静态的

静态存储区:内存在程序编译期间就已经分配完成,一般来说,这个区域在程序运行期间一直处在

它主要储存静态数据,全局静态数据和常量

二、.栈式的

执行方法时,存储局部变量(编译期间,已经确定占用内存大小),操作数,动态链接,方法出口

三、.堆式的

也叫动态内存分配,主要存储对象实例,以及已经被加载类的Class对象(用于反射)

垃圾收集器是如何判断对象是否可回收?

我们知道内存泄漏的原因是应该被回收的对象,不能被及时回收,那么GC是如何来判断对象是否为垃圾对象呢?

判断的方式有两个:

  • 引用计数 对象被引用,引用计数器加1,反之减一,只有引用计数为0,那么这个对象为垃圾对象
  • 可达性 从GCRoot节点对象开始,看是否可以访问到此对象,如果没有访问到则为垃圾对象

可以作为GCRoot对象有以下几种:

  1. 虚拟机栈中的局部变量
  2. 本地方法栈中的引用对象
  3. 方法区中的常量引用对象
  4. 方法区中的类属性引用对象

在native层和早期的虚拟机一般使用引用计数,但是现在的java虚拟机大多使用的是可达性。

什么是内存抖动?

堆内存都有一定的大小,能容纳的数据是有限制的,当Java堆的大小太大时,垃圾收集会启动停止堆中不再应用的对象,来释放内存。当在极短时间内分配给对象和回收对象的过程就是内存抖动。

内存抖动产生的原因?

从术语上来讲就是极短时间内分配给对象和回收对象的过程。 一般多是在循环语句中创建临时对象,在绘制时配置大量对象或者执行动画时创建大量临时对象。

内存抖动会带来UI的卡顿,因为大量的对象创建,会很快消耗剩余内存,导致GC回收,GC会占用大量的帧绘制时间,从而导致UI卡顿,关于UI卡顿会在后面章节讲到。

android中4种引用

  1. StrongReference强引用

从不被回收,java虚拟机停止时,才终止

  1. SoftReference软引用

当内存不足时,会主动回收,使用SoftReference使用结合ReferenceQueue构造有效期短

  1. WeakReference弱引用

每次垃圾回收时,被回收

  1. PhatomReference虚引用

每次垃圾回收时,被回收.结合ReferenceQueue来跟踪对象被垃圾回收器回收的活动。

常见的导致内存泄漏的示例

一、使用单例模式

private static ComonUtil mInstance = null;
    private Context mContext = null;

    public ComonUtil(Context context) {
        mContext = context;
    }

    public static ComonUtil getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new ComonUtil(context);
        }
        return mInstance;
    }
ComonUtil mComonUtil = ComonUtil.getInstance(this);

我们看到上面的代码就是我们平时使用的单例模式,当然这里没有考虑线程安全,请忽略。

当我们传递进来的是Context,那么当前对象就会持有第一次实例化的Context,如果Context是Activity对象,那么就会产生内存泄漏。

因为当前对象ComonUtil是静态的,生命周期和应用是一样的,只有应用退出才会释放,导致Activity不能及时释放,带来内存泄漏。

怎么解决呢?

常见的有两种方式,

第一就是传入ApplicationContext,

第二CommonUtil中取context.getApplicationContext()。

使用非静态内部类

/**
     * 非静态内部类
     */
    public void createNonStaticInnerClass(){
        CustomThread mCustomThread = new CustomThread();
        mCustomThread.start();
    }

    public class CustomThread extends Thread{
        @Override
        public void run() {
            super.run();
            while (true){
                try {
                    Thread.sleep(5000);
                    Log.i(TAG,"CustomThread ------- 打印");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

我们就以线程为例,当Activity调用了createNonStaticInnerClass方法,然后退出当前Activity时,因为线程还在后台执行且当前线程持有Activity引用,只有等到线程执行完毕,Activitiy才能得到释放,导致内存泄漏。

常用的解决方法有很多,

第一把线程类声明为静态的类,如果要用到Activity对象,那么就作为参数传入且为WeakReference,

第二在Activity的onDestroy时,停止线程的执行。

  public static class CustomThread extends Thread{
        private WeakReference<MainActivity> mActivity;
        public CustomThread(MainActivity activity){
            mActivity = new WeakReference<MainActivity>(activity)
        }
    }

使用异步事件处理机制Handler

    /**
     * 异步消息处理机制  -- handler机制
     */
    public void createHandler(){
        mHandler.sendEmptyMessage(0);
    }
    public Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            //处理耗时操作
            return false;
        }
    });

这个应该是我们平时使用最多的一种方式,如果当handler中处理的是耗时操作,或者当前消息队列中消息很多时,那当Activity退出时,当前message中持有handler的引用,handler又持有Activity的引用,导致Activity不能及时的释放,引起内存泄漏的问题。 解决handler引起的内存泄漏问题常用的两种方式:

  1. 和上面解决Thread的方式一样,
  2. 在onDestroy中调用mHandler.removeCallbacksAndMessages(null)
 @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }

使用静态变量

同单例引起的内存泄漏。

资源未关闭

常见的就是数据库游标没有关闭,对象文件流没有关闭

主要记得关闭就OK了。

设置监听

常见的是在观察者模式中出现,我们在退出Acviity时没有取消监听,导致被观察者还持有当前Activity的引用,从而引起内存泄漏。

常见的解决方法就是在onPause或者onDestory中注消监听

使用AsyncTask

    public AsyncTask<Object, Object, Object> mTask = new AsyncTask<Object, Object, Object>() {

        @Override
        protected Object doInBackground(Object... params) {
            //耗时操作
            return null;
        }

        @Override
        protected void onPostExecute(Object o) {

        }
    };

和上面同样的道理,匿名内部类持有外部类的引用,AsyncTask耗时操作导致Activity不能及时释放,引起内存泄漏。 解决方法同上:

  1. 声明为静态类,
  2. 在onPause中取消任务

使用Bitmap

我们知道当bitmap对象没有被使用(引用),gc会回收bitmap的占用内存,当时这边的内存指的是java层的,那么本地内存的释放呢?我们可以通过调用bitmap.recycle()来释放C层上的内存,防止本地内存泄漏。

摘抄

  1. Android性能优化篇之内存优化--内存泄漏

 历史上的今天

  1. 2023: ATC平台编译命令记录(0条评论)
  2. 2021: 张定浩:我喜爱一切不彻底的事物(0条评论)
  3. 2019: 林薇因:你是人间的四月天,一句爱的赞颂(0条评论)
  4. 2019: 费孝通:文字不能使人聪明起来(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

郁达夫:北平的四季

对于一个已经化为异物的故人,追怀起来,总要先想到他或她的好处;随后再慢慢的想想,则觉得当时所感到的一切坏处,也会变作很可寻味的一些纪念,在回忆里开花。关于一个曾经住过的旧地,觉得此生再也不会第二次去长住了,身处入了远离的一角,向这方向的云天遥望一下,回想起来的,自然也同样地只是它的好处。中国的大都...

Android View相关摘抄

前言介绍Android的View的相关知识(主要来自《Android进阶之光》),之前记录的,附在这里方便自己查询。正文View的继承关系ViewGroup作为View或者ViewGroup这些组件的容器, 派生了多种布局控件子类, 比如LinearLayout、 RelativeLayo...

rc文件规则简介

前言上一篇大致的走了一下init.cpp的流程,其中很重要的一环就是解析.rc文件,在介绍init.rc之前先学习一下rc文件的语法。内容主要来源参考文正文什么是rc文件在进入init.rc之前,我们需要先了解一下.rc文件。rc文件,是用Android Init Language...

WordPress评论提交速度很慢的原因和解决办法

最近使用Nana主题时,发现提交比较卡,因此百度了一下,发现大家也是一样的。由于大神也遇到,因此他们都解决了此问题,因此我也摘抄于此,以便查阅。一般分为两个问题(大多数吧),一是WordPress设置问题,二是服务器问题。1、WordPress设置问题这个比较简单,你只需要在 WordPre...

ATC平台编译命令记录

前言主要记录一下ATC项目中用的编译命令。方便自己查阅。主要是个人用,每个平台可能不一样。不推荐看哈正文在Android源码目录下隐藏内容!付费阅读后才能查看!¥2 ¥3多个隐藏块只需支付一次付费阅读参考文章1.《ATC 文档》

何其芳:脚步

你的脚步常低响在我的记忆中,在我深思的心上踏起甜蜜的凄动。有如虚阁悬琴,久失去了亲切的手指,黄昏风过,弦弦犹颤着昔日的声息;又如白杨的落叶飘在无言的荒郊,片片互递的叹息犹似树上的萧萧。呵,那是江南的秋夜!深秋正梦得酣熟,而又清彻,脆薄,如不胜你低抑之脚步!你是怎样悄悄地扶上曲...