Android 面试必备之 JVM 相关口水话,flutterpageview动画

本文深入探讨了Android面试中的JVM相关知识,包括对象的生命周期、内存管理、垃圾收集算法以及 Minor GC 和 Full GC。此外,还讨论了Java对象创建、内存布局和访问定位,以及类加载机制。同时,提到了Flutter中的PageView动画,以及Android内存管理和垃圾回收对性能的影响。
摘要由CSDN通过智能技术生成
  1. 长期存活的对象进入老年代

既然虚拟机采用了分代收集的思想来管理内存,那么内存回收就必须得识别哪些对象应放在新生代还是老年代。为了做到这一点,虚拟机给每个对象定义了一个对象年龄计数器。如果对象在 Eden 出生并经过一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将会被移到 Survivor 空间中,并且对象年龄设置为 1.对象每在 Survivor 区熬过一次 Minor GC,年龄就会增加 1。当年龄增加到一定程度,默认是 15,就将会晋升到老年代中。

最后讲一下 Minor GC 和 Full GC。

Minor GC 是指发生在新生代的垃圾回收动作,因为 Java 对象大多都是朝生夕死的,所以 Minor GC 比较频繁,回收速度也比较快。

Full GC/Major GC 指发生在老年代的 GC,出现 Full GC 经常会伴随着至少一次的 Minor GC,Full GC 一般会比 Minor GC 慢十倍以上。

Java 对象的创建、内存布局和访问定位


先说对象创建,在虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载过了,如果没有就走类加载流程。在类加载检查通过之后,虚拟机就会为新生对象分配内存,对象所需内存在类加载完成之后就确定了。为对象分配内存空间就等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式有指针碰撞和空闲列表两种,选择哪种分配方式由 Java 堆是否规整决定,而 Java 堆是否规整又由所采用的垃圾收集器是否具有压缩整理功能决定。对象创建在虚拟机是非常频繁的行为,即使是仅仅修改了一个指针指向的位置,在并发情况下也不是线程安全的。解决方案有两种,一种是采用 CAS 配上失败重试,另一种是使用线程私有的分配缓冲区 TLAB。

接着是对象的内存布局,在 HotSpot 虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头、实例数据和对其填充。可以使用 OpenJDK 开源的 JOL 工具查看对象的内存布局,直接 new Object 所占用的大小为 16 字节,即 12 个字节的对象头 + 4 个字节的对其填充。JOL 对分析集合源码扩容、HashMap 的 hash 冲突等非常有用。

最后是对象的访问定位,Java 程序需要通过栈上的 reference 数据来操作堆上的具体对象,由于 reference 类型在 Java 虚拟机规范中只规定了一个指向对象的引用,并没有规定这个引用应该通过什么方式去定位和访问堆中的对象,所以对象访问方式也是取决于虚拟机实现而定。目前主流的方式有使用句柄和直接指针两种。使用句柄,就是相当于加了一个中间层,在对象移动时只会改变句柄中的实例数据的指针,reference 本身不需要改变。HotSpot 使用的是第二种,使用直接指针的方式访问的最大好处就是速度很快。

GC


在垃圾收集器回收对象时,先要判断对象是否已经不再使用了,有引用计数法和可达性分析两种。

引用计数及可达性分析

引用计数法就是给对象添加一个引用计数器,每当有一个地方引用时就加一,引用失效时就减一。引用计数实现简单,判断效率也很高,但是 JVM 并没有采用引用计数来管理内存,其中最主要的原因是它很难解决对象之间的相互循环引用问题。可达性分析的思路是通过一系列称为 GC Roots 的对象作为起始点,从这些起始点出发向下搜索,当有一个对象到 GC Roots 没有任何引用链时,即不可达,则说明此对象是不可用的。在 Java 中,可作为 GC Roots 的对象有虚拟机栈和本地方法栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象等。

但这也并不是说引用计数一无是处,在 Android 的 Framework Native 层用的智能指针。智能指针就是一种能够自动维护对象引用计数的技术,它是一个对象而不是一个指针,但是它引用了一个实际使用的对象。简单来说,就是在智能指针构造时,增加它所引用的对象的引用计数;而在智能指针析构时,就减少它所引用对象的引用对象。但是它是怎样解决相互引用问题的呢?其实是通过强弱引用来实现,也就是将对象的引用计数分为强引用计数和弱引用计数两种,其中,对象的生命周期只受强引用计数控制。比如在解决对象 A 和 B 相互引用时,把 A 看成父 B 看成子,对象 A 通过强引用计数来引用 B,B 通过弱引用计数来引用 A。在 A 不再使用时,由于 B 是通过弱引用来引用它的,因此 A 的生命周期是不受 B 影响的,所以 A 可以安全的释放,在释放 A 时,同时也会释放它对 B 的强引用,这时 B 也可以被安全的回收了。在 Android 中,是使用 sp 来表示强引用,wp 表示弱引用。

Java 中的引用可以分为四类,强引用、软引用、弱引用和虚引用。强引用在程序中普遍存在,类似 new 的这种操作,只要有强引用存在,即使 OOM JVM 也不会回收该对象。软引用是在内存不够用时,才会去回收,JDK 提供了 SoftReference 类来实现软引用。弱引用是在 GC 时不管内存够不够用都会去回收的,可以使用 We

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值