Android内存

Android内存

垃圾回收器的职责

1、分配内存

2、确保任何能被引用的对象保留在内存中

3、回收不能通过引用关系找到的对象的内存

相关概念

垃圾回收GC

垃圾回收器中有一个进程来做上面的这些事情,这个进程查找对象引用的关系并释放内存,这个进程就是常说的GC

Heap和Stack

  • Heap内存称为堆内存,指Java运行环境用来分配给对象和JRE类的内存,是引用的内存空间

  • Stack内存称为栈内存,是对Thread而言的,它保存线程中方法中短期存在的变量和Heap中对象的引用等

  • GC针对的是Heap内存,因为Stack内存相当于是随用随销的。

GC ROOT

GC Root可以理解为Heap内存之外的对象,通常包含如下

  • System Class 系统Class Loader加载的类,如Java运行环境中rt.jar类

  • Thread运行的线程

  • JNI中的本地全局变量

  • 同步监控器 任何调用wait()或notify()方法,或者是synchronized的东西

  • Java本地实例 运行在Thread的stack中方法创建的对象

JVM内存区域


  • Young Generation

新生代,所有new的对象,该区域的内存管理使用小GC

分为三部分:Enden,Survivor 0和Survivor 1部分

  • Old Generation
    老年区,新生代中执行小粒度的GC幸存下来的老对象,该区域内存管理使用大GC
  • Permanent Generation
    持久代,包含应用的类/方法信息以及JRE库的类和方法信息
  • GC流程

    Android系统启动

    1.启动电源以及系统启动

    当电源按下时,引导芯片代码开始从预定义的地方(固化在ROM)开始执行,加载引导程序到RAM中,开始执行

    2.引导程序

    引导程序是Android程序运行开始前的一个小程序,引导程序是运行的第一个程序,主要是针对主板和芯片的。引导程序不是Android操作系统的一部分。

    引导程序执行分为两个阶段,第一阶段:检测外部的RAM以及加载对第二段有用的程序。第二阶段:引导程序设置网络、内存等。

    这些都是运行内核必要的,为了达到特殊的目的,引导程序可以根据配置参数或者输入数据设置内核。

    3.内核

    内核启动时设置缓存、被保护的存储器、计划列表、加载驱动。当内核完成系统设置后它首先在系统文件中寻找init文件,然后启动root进程或者系统的第一个进程。

    4.init进程

    init是第一个进程,它是root进程的父进程。init进程有两个责任,一是挂载目录,二是运行init.rc脚本。

    5.Zygote

    在Java中,不同的虚拟机实例会为不同的应用分配不同的内存。如果Android系统为每一个应用启动不同的虚拟机就会消耗大量的内存以及时间。为此Android系统创造了Zygote,Zygote让虚拟机共享代码、低内存占用和最小时间启动称为可能。Zygote是一个虚拟器进程在系统引导的时候启动。Zygote预加载以及初始化核心类库。在Java虚拟机中,每一个实例都有它自己的核心类库文件和堆对象的copy。

    ServiceManager和Zygote进程是Android的基础,Zygote进程起来了才会建立真正的Android运行空间。

    Zygote建立完成后利用Socket通讯,接收ActivityManagerService的请求,fork应用程序。

    6.系统服务System Server

    Android的所有服务循环框架都是建立在SystemServer上的,其中通过AddService来添加服务到ServiceManager中。

    7.流程

    Linux系统通过init在启动若干守护进程后,就启动了Android的runtime和Zygote,Zygote再启动虚拟机、系统服务,系统服务再启动完本地服务后,有启动若干的Android服务,并完成ServiceManager的注册工作,最后整个系统启动完成。其中Zygote孵化器为各个进程以复制的方式用最小的代价实现了虚拟机。

    内存泄露

    Android中导致内存泄露的原因有单例导致的内存泄露,内部类导致的内存泄露,匿名内部类导致的内存泄露,静态内部类导致的内存泄露等。

    1.单例导致的内存泄露

    创建单例类,代码如下

    public class SingleManager {
            private Context mContext ;
            private static SingleManager instance ;
            //初始化需要Context上下文对象
            private SingleManager (Context context){
                this.mContext = context ;
            }   
            public static SingleManager getInstance(Context context){
                if(instance == null){
                    synchronized(SingleManager.class){
                        if(instance == null){
                            instance = new SingleManager(context);
                        }
                    }
                }
                return instance ;
            }
        }

    在activity中调用,调用方式如下

    public class MainActivity extends AppCompatActivity {
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                //调用,直接传入this对象
                SingleManager.getInstance(this);
            }
        }

    配置好LeakCanary,然后直接点击返回按钮,LeakCanary会报异常,如图

    通过LeakCanary可以看到,报出了内存泄露的异常,是由于单例引起的内存泄露。

    在activity中使用单例时传入的参数是this对象,该this是activity,当点击返回按钮退出activity时,activity本应该被销毁,但是因为该activity被单例引用,所以不会被销毁,导致activity不会被回收,这就导致了内存泄露,那么我们如何避免这种情况产生呢。内存泄露是由于activity没有没回收引起的,所以我们可以不引用activity,可以直接引用application对象。代码修改如下。

    public class SingleManager {
            private Context mContext ;
            private static SingleManager instance ;
            //初始化需要Context上下文对象
            private SingleManager (Context context){
                this.mContext = context.getApplicationContext() ;
            }   
            public static SingleManager getInstance(Context context){
                if(instance == null){
                    synchronized(SingleManager.class){
                        if(instance == null){
                            instance = new SingleManager(context);
                        }
                    }
                }
                return instance ;
            }
        }

    通过在单例中将context对象转成application对象就可以解决该问题了。无论传入的是activity还是application,在单例中我们使用的都是application对象。

    2.Handler导致的内存泄露

    在Java中非静态内部类和匿名内部类都持有外部类对象,所以如果在activity中创建非静态内部类或者匿名内部类,所以如果activity被关闭但是内部类还被其他对象持有时,activity不会被销毁,这就导致了内存泄露。具体示例如下

    public class MainActivity extends AppCompatActivity {
    
            private Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    switch(msg.what) {
                        case 0:
                            //TODO
                            break;
                        case 1:
                            //TODO
                            break;
                        default:
                            break;
                    }
                }
            };
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                handler.sendEmptyMessage(0);
            }
        }

    在activity中创建一个handler匿名内部类,在onCreate()方法中调用sendEmptyMessage()方法,系统会发送消息到消息队列中,该消息包含一个target,该target对象是activity中匿名handler对象,这时候如果消息队列中消息过多,该消息暂时没有被处理,同时activity被关闭,这时就会引起内存泄露。

    如何解决该问题呢?

    可以通过弱引用WeakReference来解决该问题。

    修改代码如下

    public class MainActivity extends AppCompatActivity {
            private static class MyHandler extends Handler {
                //使用弱引用
                WeakReference<MainActivity> wrf ;
                public MyHandler (MainActivity activity) {
                    if(activity != null) {
                        wrf = new WeakReference<MainActivity>(activity) ;
                    }
                }
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    if(wrf == null)return ;
                    //使用弱引用来获取activity
                    MainActivity activity = wrf.get();
                }
            }
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                MyHandler handler = new MyHandler(this) ;
                handler.sendEmptyMessage(0);
            }
            @Override
            protected void onDestroy() {
                super.onDestroy();
                MyApplication.getRefWatcher().watch(this);
            }
        }

    3.内部类导致的内存泄露

    内部类引起的内存泄露示例如下

    public class MainActivity extends AppCompatActivity {
            //内部类
            class InnerClass {
            }
            //静态内部类对象
            private static InnerClass innerClass ;
            //创建内部类对象
            private void createInnerClass(){
                innerClass = new InnerClass() ;
            }
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                createInnerClass();
            }
        }

    activity中创建内部类,并且使用静态对象持有该内部类对象,被static修饰的变量声明周期是整个源程序的生命周期,与activity生命周期无关,所以当activity被关闭时innerClass变量不会被清空,依然存在内存中,innerClass变量持有内部类对象,间接的持有外部类的MainActivity对象。导致MainActivity不会被回收,导致出现内存泄露,LeakCanary检测如下

    4.匿名内部类导致的内存泄露

    匿名内部类导致内存泄露如下示例如下

    public class MainActivity extends AppCompatActivity {
            void startAsyncTask() {
                new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        while(true);
                    }
                }.execute();
            }
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                startAsyncTask();
            }
        }

    在activity创建匿名内部类,匿名内部类中执行线程,当activity退出时,线程依然在执行,这个匿名内部类依然存在,匿名内部类只有外部类activity,这就导致activity不会被回收,导致内存泄露。

    LeakCanary检测如下

    QQ交流群

    微信公众号:Android在路上,欢迎关注

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值