history

Dalvik

  • 使用解释 JIT

ART(4.4Kitkat-5.0Lollipop) Android RunTime

  • gc优化
  • AOT(Ahead-of-time)

ART(7.0Nougat)

  • 三种执行方式并存,引入speed profile

overview

  • compiler&interpreter
    • 解释器
    • JIT
    • AOT
  • runtime
    • 内存管理
    • 类管理
    • intrinsic
    • 异常
    • String
    • 调试
    • 线程
    • JNI
    • monitor

对象

对象如何分配出来的

who = 类的管理
from where = 内存分配
to where = 内存回收

对象lifecycle

  • 对象分配
    • 分配多大 - 类
    • 怎么分配 - 内存管理
  • 对象使用
    • 执行类的方法
    • 访问对象成员
  • 对象销毁
    • 内存回收 - GC && 清理

类管理 - 决定一个对象的大小和行为

  • 类主要描述的是一个对象的内存布局和函数信息

  • 内存布局: 类成员的大小、类型和排布

  • 函数信息: 主要是虚表的信息-某个函数定义在当前类函数表的第几个位置;因为java是支持继承的,因此类的捏成布局和函数虚表需要做继承链全展开以后才能真正确认(这也是动态性的来源)

    类管理 - 基类Object的秘密

  • 类加载

    • 一个类分配的对象大小,是由继承链决定的
    • Java的类,是在第一次使用的时候,才会进行加载
  • 内存布局

  • 双亲继承

    • 本质上,双亲委派就是认为划定的一个规矩,保证系统内同一个类的一致性
  • 合理的继承抽象的好处

    • 合理的抽象,不是因为图方便直接放在顶层基类上,这就是好处

      内存分配

  • 分配器 - APP的java对象内存分配是托管到VM来处理的,并不会直接向操作系统去申请,实际上对OS内存的占用和内存布局,是VM控制的(预留-扩展)

  • 不同分配器的特点

  • 典型场景

    • bitmap在Android高版本,被隐藏到了native,不直接使用虚拟堆;内存一样,量小,方便快捷,但是大块儿的内存用起来慢,要从大池子里取,集中管理
  • 内存碎片

    • ART内存分配的根本原理,给使用者在最优范围内找到一块大小符合的连续内存
    • 希望可用内存尽可能连续

内存回收

  • GC(垃圾回收garbage collection),要定期查找系统内不用的对象,并且释放占用的内存
  • RC(引用计数reference counting),指的是对一个对象引用进行计数,多一个引用者,就+1,少一个,-1,为0就释放;典型的如IOS的swift就使用RC进行内存管理
  • RC的问题和解决
  • ART的引用
    • 强引用:直接持有的
    • 软引用:内存不够时候会回收
    • 弱引用:只要触发GC就会被回收
  • 触发GC的条件
    • 想要不被预期外的GC导致卡顿,可以考虑适当预留内存
    • 大小有上限可预期的情况,new一个大数组,比分配一大堆到容器里面要好
  • apple内存少的原因之一
  • GC的方式
    • GC roots的概念
  • tracing GC
    • 从roots遍历,所有mark的对象是有holder的,释放掉没有holder的object
  • copying GC
    • 从roots遍历,把有用的对象拷贝到另一个区域,然后集中释放掉当前区域的内存
  • ART的做法
    • 前台GC | 后台GC
  • 内存友好的代码
  • 回收之后
    • finalize方法一般用来跟随对象的生命周期,清理掉绑定的native资源
    • 一个对象的finalize方法只会执行一次,再次激活之后的对象是不会出发finalize的

      执行

      虚拟机为了保证代码执行提供的机制

      虚拟机的执行方式

  • 解释执行-dex code
  • JIT-profile-JIT compile-JIT code
  • AOT- speed-profile -dex2oat-AOT code
    • 在程序运行之前,对APK中的函数进行编译
    • 和程序是否运行无关
    • 编译的范围不是以函数为单位,以dex为单位
    • 结果会持久化
  • 延迟绑定(绑定的越迟,动态性越好,性能越差)

    栈管理 - 开始和结束

  • ART对于解释执行和编译后指令采用不同的策略
    • 对于解释执行-栈托管到虚拟机完成
    • 对于编译后的-压栈处理和native代码是一样的,遵从对应指令集的约定
  • 不同执行方式之间的切换
    • 对于AOT,JIT到解释执行,或者反之的调用,ART采用trampoline-bridge机制来进行切换
  • 总结
    • 压栈-出栈的速度不同,解释执行的速度慢
    • 解释执行的栈结构是托管的,编译执行的栈结构是遵从虚拟机规则的
    • 解释执行传递参数有额外的空间成本,编译执行没有
    • 不同执行方式之间调用切换采用trampoline/bridge进行

      异常处理

  • 当拿到一个异常的时候,会逐级回栈
    • 回一级栈看看要不要
    • 不要就跳出

      多线程 - 高效的执行

  • synchronize
    • JAVA 引入sync机制,让我们加解锁很方便

同步机制

  • monitor:如果我们对一个对象是用了sync,这个对象就会生成一个lock,保留在这个shadow monitor指向的内存地址中

  • 胖瘦锁切换

  • 深入理解Android-Java虚拟机ART

  • 虚拟机设计与实现-以JVM为例