深入理解java虚拟机
- java体现架构可以分为:java设计语言、java API、class文件、虚拟机
- 一个java程序都有一个java虚拟机实例.一个java虚拟机实例有单独的堆、方法区、栈等.
类加载器
java平台的类加载器
- Bootstrap ClassLoader. 引导类加载器由C++ 实现的加载器,加载Java的核心类库.
- Extensions ClassLoader. 拓展类加载器
- Application ClassLoader 应用程序类加载器.可以通过getSystemClassLoader获取到.
Android平台的类加载器
- BootClassLoader. 在Zygote进程的 main方法中加载.
- PathClassLoader 继承自 BaseDexClassLoader. 应用安装完成后,会使用此类,按照
DexPathList
中 dex 元素的顺序加载dex文件. 在SystemServer进程中加载. - DexClassLoader, 继承自 BaseDexClassLoader
双亲委派模型
- 类装载器优先使用双亲装载器去装载类型,如果双亲装载器装载失败,那么类装载器才会尝试自己装载类.
- 启动类装载器是根类装载器,由native方法实现.
- 每一个类装载器都有一个唯一的命名空间,通过命名空间控制了类的访问权限.
- 装载、连接、初始化.
内存相关
- 方法区. 装载的类信息存放在方法区.类型、字段信息、常量池、方法信息等等
- 堆. 分配的实例对象存放在堆中.
- 栈
- 程序计数器
知识点
- 对象的引用指向了堆中的对象实例,对象的引用也指向了方法区中的类信息,这个类信息是对象的实际类型,是运行时的类型.
- 数组在虚拟机中对应的类型仅与数组的类型和维度有关.
- 在java虚拟机中出现的整数运算溢出并不会导致异常,而仅仅是简单的将溢出部分截断,以符合数据类型.
查看class文件
- hexdump 可以查看class文件的16进制输出
- javap -v name.class 可以查看class文件的字节码流,包括操作码
- java class文件是二进制的码流,按照顺序解析
类加载
- 装载、连接、初始化.
- 连接分为:验证、准备(分配内存,初始化默认值)、解析
- 加载子类前优先加载父类,初始化子类前优先初始化父类.
- 只有主动使用的场景下,才会触发初始化. 用子类调用父类的非final的静态变量,并不会导致子类初始化.
- 静态常量(final static)不会导致类的初始化.
垃圾收集算法
- 新生代. 常用算法为复制算法. 标记有效的内存区域,复制到空白内存区, 原来的内存区域直接清除.
- 老年代. 常用算法为标记-清除或者标记压缩算法.
- 永生代. 类信息、静态常量等信息
Android 中常见的GC roots
- 系统类加载器加载的对象
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- 方法区中的类静态属性引用的对象。
- 方法区中的常量引用的对象。
- 本地方法栈中JNI(Native方法)的引用对象。
- 存活的线程对象
GC root和内存泄露
- 当发生内存泄露的时候,可以根据GC roots 去找泄露的对象