《深入理解Java虚拟机》学习笔记
Posted 吴豪杰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《深入理解Java虚拟机》学习笔记相关的知识,希望对你有一定的参考价值。
本系列文章为《深入理解Java虚拟机: JVM高级特性与最佳实践》阅读笔记。
垃圾收集器与内存分配策略
引用计数法
: 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器都为0的对象就是不可能再被使用的。但是,其不能解决对象之间的相互循环引用的问题。Java和C#,甚至包括古老的Lisp,都是使用
根搜索算法
判定对象是否存活的。该算法通过一系列「GC Roots」对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到「GC Roots」没有任何引用链相连(用图论的话来说就是从「GC Roots」到这个对象不可达)时,则证明此对象是不可用的。
在Java中,「GC Roots」包括:- 栈中引用的对象
- 静态引用对象
- 常量引用对象
- JNI所引用的对象
Java中引用分为:
强引用
(不被回收)、软引用
(内存不足进行第二次回收)、弱引用
(随时回收)、虚引用
(最弱的关系,不能取得实例)。- 如果覆写了
finalize()
方法且有必要,虚拟机会触发finalize()
方法,且只会调用一次,但并不承诺会等待它运行结束。 - 回收常量: 判断有无对象引用常量池中的常量;
回收类: 满足下列三个条件才可以被回收。
- 该类的所有实例都被回收
- 加载该类的ClassLoader已经被回收
- 该类对应Class对象没有在任何地方被引用
垃圾收集算法: 「标记清除算法」、「复制算法」、「标记整理算法」、「分代收集算法」。
- 垃圾收集器(7种作用于不同分代的收集器): Serial收集器(Stop the World)、ParNew收集器(多线程版Serial)、Parallel Scavenge收集器、CMS(并发收集、低停顿)、G1收集器(Java 1.7、标记整理、精准控制停顿)
内存分配策略:
- 对象优先在Eden分配
- 大对象直接进入老年代,如数组、字符串
- 长期存货的对象将进入老年代,默认年龄达到15岁进入,当然并不是一定达到才可以进入
空间分配担保: 每次晋升到老年代的平均大小如果大于老年代的剩余空间大小,则进行一次「Full GC」
Minor GC: 新生代GC;Full GC: 老年代GC
类文件结构和类加载
魔数与Class文件版本: 很多图片文件头都存有魔数,比如gif或jpeg。Class文件的魔数是0xCAFEBABE。魔数后面分别是2个字节的次版本号和2个字节的主版本号。版本号从45开始的。
版本号后面紧跟的是常量池容量计数值,从1开始计数。(P143)
- 类加载时会先加载父类,接口则只在用到父接口的时候才加载。
- 类加载过程:
加载
->验证
->准备
->(解析)
->初始化
->使用
->卸载
解析在某些情况下可以在初始化阶段之后再开始
static
变量在准备阶段就已经分配内存,但通常情况不会为其赋值初始化,初值为0,除非存在final
修饰,那样便会立即初始化。对于静态变量和静态代码块,编译器先变量赋值,再静态代码块。且先执行父类,即Object中的静态代码块先于任何一个类中的变量赋值和静态代码块。- 两个类相等不仅要「Class对象相等」,而且「ClassLoader也要相等」。
双亲委派模型
: 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
虚拟机字节码执行引擎
局部变量Slot回收要满足:
- 超出作用域
- 有新的局部变量覆盖Slot区
操作数栈
: 例如加法运算中的两个数栈帧信息
: 一般会把动态连接(指向方法等的符号连接)、方法返回地址与其他附加信息全部归位一类,称为栈帧。- 对于静态等已经确定了的方法(不会被覆写),调用时直接将符号引用转化为直接引用,这种调用方法称为解析。Java虚拟机中方法调用对应四条指令:
- invokestatic: 调用静态方法
- invokespecial: 调用实例构造器、私有方法和父类方法
- invokevirtual: 调用所有的虚方法,和final修饰的方法
- invokeinterface: 调用接口方法
待续
以上是关于《深入理解Java虚拟机》学习笔记的主要内容,如果未能解决你的问题,请参考以下文章