序言
岁月悠悠,衰微只及肌肤;热忱抛却,颓唐必致灵魂
今天来总结一下JVM。
JVM的整体结构
JDK:JVM + 基础类库 + 编译工具;
JRE:JVM + 基础类库;


说明:
- 线程私有:虚拟机栈,本地方法栈,程序计数器;
- 线程共享:堆,方法区;
- 执行引擎:解释器(Interpreter)、JIT(即时编译器,编译器后端)、GC(垃圾回收器);
- JVM直接和操作系统对话;
- 先经过类加载器,类信息放在方法区中,类的实例对象放在堆中;
- 解释器逐行解释代码,翻译成机器码;
栈是属于线程的,堆是属于进程的
此外,stack创建的时候,大小是确定的,数据超过这个大小,就发生stack overflow错误,而heap的大小是不确定的,需要的话可以不断增加。
Java代码执行流程

JVM的架构模型


JVM的生命周期


说明:
jps查看JVM进程
类加载子系统






加载:




讲图:
instanceKlass相当于一种数据结构;
堆中存放Person.class的类对象,这个类对象有instanceKlass的内存地址
instanceKlass也存放着Person类对象的内存地址;
对于Person的实例化对象来说,对象头部存放Person类对象地址;
那么就会先去找class类对象,再间接去元空间去找instanceKlass对象,再之后就会去元空间里面找_Methods,_fields,去调用对象方法。
链接:

验证:
文件格式验证:0xCAFEBABE
元数据验证:对字节码描述的信息进行语义分析
字节码验证:最复杂
通过数据流分析和控制流分析,确定程序是合法的,符合逻辑的
符号饮用验证:确保解析行为可以正常运行
准备:
- 对于final,static:
- 基本类型会直接给值
- 包装类就会先0再赋值
- 在JDK7之后,静态变量的内存不再方法区内,会跟着类对象存储在堆中。
- 常量也会在准备阶段被赋值;
解析:其实就是
#1->内存指针的过程;初始化:


讲图:
()就是给类变量赋值; 类一旦被初始化,那么static{}代码块就会执行;
类加载器分类




启动类加载器

扩展类加载器

应用程序类加载器


用户自定义类加载器



关于ClassLoader




双亲委派机制



沙箱安全机制

类的主动使用和被动使用



运行时数据区




程序计数器







说明:
并行是时刻,并发是时间段;
并行是同时执行,并发是一个时间片内交替执行;

虚拟机栈


说明:
栈空间也可以存放堆中对象的引用值;
栈:每个【线程】运行时需要的内存空间,每个线程只能有一个活动栈桢;
栈桢:每个【方法】运行时需要的内存空间:
局部变量表/操作数栈/动态链接/返回地址
活动栈桢:对应着当前正在执行的方法,往往在栈顶部;






局部变量表




说明:静态方法是不允许使用this关键字的



操作数栈
它是由数组实现的




Demo


栈顶缓存技术

动态链接

运行时常量池在方法区中;

方法的调用



虚方法和非虚方法


this/super基本上都是非虚方法,在编译期间就可以确定
invokestatic/invokespecial

如果隐式调用父类的final方法(也就是不加super.),是invokevirtual
但如果super.的方式,则是invokespecial
子类重写也是invokevirtual



方法重写


方法返回地址


本地方法接口




本地方法栈


