JVM 是用来解析和运行 Java 程序的,在 JDK 的 bin 目录
JRE - Java Runtime Environment
java 运行时环境,由 JVM(bin 目录) 和 java 类库(lib 目录)组成
JDK - Java Development Kit
java 最小开发环境,由 JRE 和 开发者工具 组成
OpenJDK 免费开源,Oracle JDK 生产环境商用要收费
Oracle JDK 比 OpenJDK 更稳定,性能更好
HotSpot VM 从 JDK 1.3 到 JDK 8 是 Sun/Oracle JDK 和 OpenJDK 默认的 Java 虚拟机
java 跨平台
java 编译器把 java 编译成一种跨平台的中间代码叫字节码, 存在 class 文件里, 各平台的 java 虚拟机都可以解释执行字节码,一次编译,处处运行
热点代码探测技术
通过执行计数器找出最具有编译价值的代码,通知即时编译器以方法为单位编译成物理硬件可直接执行的机器码
某个方法被频繁调用,触发标准即时编译
某个方法中有效循环次数很多,触发栈上替换编译 (OSR - On-Stack Replacement)
HotSpot VM 执行子系统 由编译器与解释器构成
通过编译器和解释器协同工作,在响应时间和执行性能中取得平衡
对象的创建过程
1.类加载
先检查指令的参数是否能在常量池中定位到一个类的符号引用,
并检查这个符号引用所代表的类是否已被加载,如果没有,
就先执行相应类的加载过程
2.为新对象分配内存
指针碰撞 bump the pointer
如果 堆 中的内存是绝对规整的,已使用内存和空闲内存各在一边,通过一个指针,把已使用内存和空闲内存分隔开,分配内存时,只需将指针向空闲内存移动一段与对象大小相等的距离
空闲列表 free list
如果 堆 中的内存是不规整的,已使用内存和空闲内存相互交错,虚拟机需维护一个列表,记录可用的内存块,分配的时候在列表里,找到一块足够大的内存,划给对象实例,并更新列表上的记录
分配方式由堆是否规整决定
带整理功能的收集器,分配算法采用指针碰撞,如 Serial, ParNew
基于标记清除算法的收集器,分配算法采用空闲列表,如 CMS
分配内存的线程安全性问题
同步处理
通过 CAS 加 失败重试 来保证更新操作的原子性
本地线程分配缓冲 TLAB - Thread Local Allocation Buffer
每个线程在 JAVA堆 中分配一小块内存作为分配缓冲区,某个线程要分配内存的时候,就从对应的 本地线程分配缓冲区 中分配,当本地缓存区用完之后,分配新的缓冲区时,才需要同步锁定
虚拟机是否使用 TLAB , 可以配置 -XX: +/-UseTLAB
3.把对象的实例字段初始化为零值
4.设置对象头信息
对象的类型信息,GC分代年龄等
5.调用构造函数
----------------------------------------------------
JVM 的整体结构
JVM 存在三个系统,类加载子系统,运行时数据区,执行引擎
类加载子系统把字节码加载到运行时数据区的方法区中
运行时数据区分为方法区 堆 虚拟机栈 本地方法栈 程序计数器
执行引擎包括解释器 即时编译器 垃圾回收器
解释器负责解释执行字节码
即时编译器会把热点代码编译成机器码提高执行性能
垃圾回收器负责垃圾回收
----------------------------------------------------