虚拟机(Virtual Machine)
虚拟机就是一台虚拟的计算机,是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。
- 系统虚拟机,如VMware,完全是对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台
- 程序虚拟机,如JVM,它专门为执行单个计算程序而设计,在JVM中执行的指令称为Java字节码指令
Java虚拟机(JVM)
目前默认用的是HotSpot,可以通过
java -version
命令的输出信息查看
Java虚拟机是一台执行Java字节码的虚拟计算机,它拥有独立的运行机制,其运行的Java字节码也未必是用Java语言编译而成,也就是说,其他语言如JavaScript、Jython、Scala等经过它们自己的编译器编译为字节码文件后,这些字节码文件只要遵循Java虚拟机规范,Java虚拟机就能执行这些程序。
JVM平台的各种语言可以共享JVM带来的跨平台性、优秀的垃圾回收器,以及可靠的即使编译器。
Java虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部解释/编译为对应平台上的机器指令执行。每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在那里。
JVM发展简史
(1)1996年1月,Sun发布jdk1.0,发布名为Classic VM的Java虚拟机,是世界上第一款商用JVM,在jdk1.4时被淘汰
- 只提供解释器,如果需要使用即时编译器,就要进行外挂,但是解释器和JIT编译器不能同时使用
(2)Exact VM
- jdk1.2时发布了此虚拟机,解释器和JIT编译器可以混合工作
(3)HotSpot
- Longbiew Technologies公司研发了HotSpot VM,1997年被Oracle收购该公司后获得了这个虚拟机,HotSpot继承了上面两款虚拟机的优点,HotSpot指的就是它的热点代码探测技术。HotSpot虚拟机的热点代码探测能力可以通过执行计数器找出最具有编译价值的代码,然后通知即时编译器以方法为单位进行编译。如果一个方法被频繁调用,或者方法中有效循环次数很多,将会分别触发标准即使编译器和栈上替换编译行为。通过编译器与解释器恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无须等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更复杂的代码优化技术,输出质量更高的本地代码。
- jdk1.3的默认虚拟机就是HotSpot,一直使用至今
(4)JRockit
- 专注于服务端应用,不太关注程序启动速度,因此JRockit内部不包含解释器实现,全部代码都靠编译编译后执行
(5)…还有很多JVM
JVM整体结构
蓝色区域是所有线程共享的数据区,其他是线程隔离的数据区
JAVA执行流程图解
JIT(Just In Time)即时编译,将访问频率高的代码(称为热点代码)以方法为单位编译成机器指令存放到方法区中,下次再执行到热点代码的时候,就不需要逐行解释字节码成机器指令,而是直接使用编译好的机器指令,提高执行效率。
解释器由于能立即解释执行程序,因此得到更快的程序响应时间,而JIT编译器由于需要搜索热点代码,编译等过程导致响应时间没有解释器块,但是一旦程序编译好,则执行性能大大提高。因此编译器和解释器的协同工作,在最优化的程序响应时间与最佳执行性能中取得平衡。
JVM的生命周期
虚拟机的启动
Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
虚拟机的执行
- 程序开始执行时虚拟机开始运行,程序结束时虚拟机停止
- 执行一个Java程序的时候,真正执行的是一个叫做Java虚拟机的进程
虚拟机的退出
有如下几种情况会导致虚拟机退出:
- 程序正常执行结束
- 程序在执行过程中遇到了异常或错误而异常终止
- 由于操作系统出现错误
- 某线程调用Runtime类或System类的eixt方法,或Runtime类的halt方法,并且Java安全管理器也允许这次exit或halt操作
JVM线程系统
使用jconsole或者其他调试工具会看到有许多线程在运行,这些后台线程不包括调用main方法的main线程以及所有这个main线程自己创建的线程。
这些后台系统线程在HotSpot JVM里主要是:
- 虚拟机线程
这种线程的执行类型包括“stop-the-world”的垃圾收集,线程栈收集,线程挂起以及偏向锁撤销 - 周期任务线程
这种线程是时间周期事件的体现(比如中断),他们一般用于周期性操作的调度执行 - GC线程
这种线程对在JVM里不同种类的垃圾收集行为提供了支持 - 编译线程
这种线程在运行时会将字节码编译到本地代码 - 信号调度线程
这种线程接受信号并发送给JVM,在它内部通过调用适当的方法进行处理