卧槽,Android篇

本文详细介绍了Android中垃圾回收的两种主要机制——引用计数和可达性分析,通过实例解析了这两种机制的工作原理,并指出可达性分析能解决对象相互引用的问题。此外,文章还探讨了栈中局部变量、静态变量作为GcRoot的情况,并简单概述了标记清除和复制两种常见的垃圾回收算法。最后,作者分享了Android开发的学习资源和心得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2.1 引用计数

什么是引用计数呢?打个比方A a = new A(),代码中 A 对象被引用 a 所持有,此时引用计数就会 +1 ,如果 a 将引用置为 nulla = null此时对象 A 的引用计数就会变为 0 ,GC算法检测到 A 对象引用计数为 0 就会将其回收。很简单,但引用计数存在一定弊端

场景如下:


A a = new A();

B b = new B();

a.next = b;

b.next = a;

a = null;

b = null;



执行完上述代码后 AB 对象会被回收吗?看似引用都已经置为 null ,但实际上 abnext 分别持有对方引用,形成了一种相互持有引用的局面,导致AB 即使成了垃圾对象且不能被回收。有些同学可能会说,内存泄漏太容易看出来了, ab 置空前将各自的 next 置为空不就完了。嗯,这样说没错,但是在实际业务中面对庞大的业务逻辑内存泄漏是很难一眼看出的。所以JVM在后来摒弃了引用计数,采用了可达性分析。

2.2 可达性分析

可达性分析其实是数学中的一个概念,在JVM中,会将一些特殊的引用作为 GcRoot ,如果通过 GcRoot 可以访达的对象不会被当作垃圾对象。换种方式说就是,一个对象被 GcRoot 直接 或 间接持有,那么该对象就不会被当作垃圾对象。用一张图表示大概就是这个样子:

图中A、B、C、D可以被 GcRoot 访达,所以不会被回收。E、F不能被 GcRoot 访达,所以会被标记为垃圾对象。最典型的是G、H,虽说相互引用,但不能被 GcRoot 访达,所以也会被标记为垃圾对象。综上所述: 可达性分析 可以解决 引用计数 中 对象相互引用 不能被回收的问题。

什么类型的引用可作为 GcRoot 呢。 大概有如下四种:

  • 栈中局部变量
  • 方法区中静态变量
  • 方法区中常量
  • 本地方法栈JNI的引用对象
注意点

千万不要把引用和对象两个概念混淆,对象是实实在在存在于内存中的,而引用只是一个变量/常量并持有对象在内存中的地址指。

下面我来通过一些代码来验证几种 GcRoot

局部变量

笔者是用Android代码进行调试,不懂Android的同学把onCreate视为main方法即可。


public class MyApp extends Application {



    @Override

    public void onCreate() {

        super.onCreate();

        method();

    }



    private void method(){

        Log.i("test","method start");

        A a = new A();

        try {

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        Log.i("test","method end");

    }



    class A{

        @Override

        protected void finalize() throws Throwable {

            Log.i("test","finalize A");

        }

    }

}



提示

  • 在java中一个对象被回收会调用其finalize方法
  • JVM中垃圾回收是在一个单独线程进行。为了更好的验证效果,在此加2000毫秒延时

打印结果如下:


17:58:57.526   method start

17:58:59.526   method end

17:58:59.591   finalize A



method 方法执行时间是2000毫秒,对象Amethod 方法结束立即被回收。所以可以认定栈中局部变量可作为 GcRoot

本地方法区静态变量

public class MyApp extends Application {



    private static A a;

    @Override

    public void onCreate() {

        super.onCreate();

        Log.i("test","onCreate");

        a = new A();

        try {

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        a = null;

        Log.i("test","a = null");

    }

}



打印结果如下:


18:12:35.988   a = new A()

18:12:38.028   a = null

18:12:38.096   finalize A



创建一个 A 对象赋值给静态变量 a , 2000毫秒后将静态变量 a 置为空。通过日志可以看出对象 A 在静态变量 a 置空后被立即回收。所以可以认定静态变量可作为 GcRoot

方法区常量与静态变量验证过程完全一致,关于native 验证过程比较复杂,感兴趣的同学可自行验证。

验证成员变量是否可作为 GcRoot

public class MyApp extends Application {



    @Override

    public void onCreate() {

        super.onCreate();

        A a = new A();

        B b = new B();

        a.b = b;

        a = null;

    }



    class A{

        B b;

        @Override

        protected void finalize() throws Throwable {

            Log.i("test","finalize A");

        }

    }



    class B{

        @Override

        protected void finalize() throws Throwable {

            Log.i("test","finalize B");

        }

    }

}



打印结果如下:


13:14:58.999   finalize A

13:14:58.999   finalize B



通过日志可以看出,A、B 两个对象都被回收。虽然 B 对象被 A 对象中的 b 引用所持有,但成员变量不能被作为 GcRoot, 所以B 对象不可达,进而会被当作垃圾。

3. 回收算法


上一小结描述了 GC 机制,但具体实现还是要靠算法,下面我简单描述一下几种常见的 GC算法

3.1. 标记清除算法

获取所有的 GcRoot 遍历内存中所有的对象,如果可以被 GcRoot 就加个标记,剩下所有的对象都将视为垃圾被清除。

  • 优点:实现简单,执行效率高
  • 缺点:容易产生 内存碎片(可用内存分布比较分散),如果需要申请大块连续内存可能会频繁触发 GC

3.2. 复制算法

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

CodeChina开源项目:《Android学习PDF+架构视频+面试文档+源码笔记》

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-or553eBf-1631093550285)]

CodeChina开源项目:《Android学习PDF+架构视频+面试文档+源码笔记》

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值