深入理解Java虚拟机
Java虚拟机发展史
从1996年初sun公司发布的jdk1.0中所包含的sun Classic VM到今天,曾经涌现或消失过许多经典和特色的虚拟机出现。Classic VM只能使用纯编辑器来执行。如果要使用jit编辑器必须使用外挂。执行效率和传统的c/c++程序有很大差异,“Java语言很慢”就是在这个时候在用户中树立起来的。
Sun公司努力去解决classvm的问题,为了提升运行效率,在jdk1.2使用了exact vm 它的执行系统已经具备现代高性能虚拟机的雏形。编译器和解释器混合工作模式。虽然比第一代先进了许多,但在商业中只存在了很短暂的时间就被hotspot vm所取代,甚至还没来的及发布windows和linx下的商用版本。
提起hotspotvm。它是sun jdk 和open jdk中所带的虚拟机,也是目前使用范围最广的Java虚拟机。继承了上两代虚拟机的优点。
热点代码和探测技术,hotSpot热点探测能力可以通过执行计数器找出最具有编译价值的代码,然后通过jit以方法为单位进行编译。
Java技术的未来是趋向于模块化的,技术平台越来越复杂,越来越庞大。当单一的Java开发无法满足当前软件的复杂需求,越来越多的Java虚拟机的语言开发被应用到我们的软件项目中。
如今,cpu硬件的发展方向已经从高频率转化为多核心,软件开发越来越关注并行编程的领域。Jdk1.5 引入了Java.util.concurrent包实现了粗粒度的并发框架。而1.7的forkjoin包则包含了对这个框架的一次重要扩充。Jdk1.8提供lambda 极大的改善了Java语言不适合函数式编程的现状。在几年之前,主流的cpu就支持64位架构了。,Java也早早地推出了支持64位的版本。
想要精通jdk内部的实现机制,最便捷的路径是自己编译一套jdk,虽然门槛高很多,但肯定比阅读书籍,文章更贴近本质,怎么获取jdk源码?Source bundle releases 获取打包好的源码。大概99M,解压后约 339M。
Java虚拟机在执行Java程序的过程中,会把它所管理的内存划分为若干个不同的数据区。这些区域有各自的用途,有的区域随着随着虚拟机进程的启动而存在。有些区域则依赖于用户线程的启动和结束建立和销毁。
程序计数器是一块较小的内存空间,它可以看作当前线程执行字节码的行数指示器。每条线程都需要一个独立的程序计数器。线程之间计数器互不影响。如果线程正在执行一个方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址:如果正在执行native方法。这个计数器值则为空,此内存区域是唯一一个虚拟机没有任何outofmemoryError的区域。
Java虚拟机栈也是线程私有的,虚拟机栈是Java方法执行的内存模型,存储局部变量表,操作数栈,方法出口,动态链接等信息。如果线程请求的栈深度大于虚拟机所允许的深度,抛出stackOverFlowError。本地方法栈为虚拟机使用native方法使用。
Java堆是管理内存中最大的一块,是所有线程共享,存放对象实例。有的时候也被成为GC堆,采用分代收集算法,分为新生代和老生代 如果堆无法继续扩展并且实例无法内存分配。抛出outofmemoryError。方法区和堆一样,各个线程共享的内存区域。存储类信息,常量,静态变量,即时编译器编译后的代码等数据。运行时常量池是方法区的一部分。直接内存并不是虚拟机运行的一部分,也不是Java规范的内存区域,在jdk1.4加入nio,引入基于通道的缓冲区的I/o方式,它可以使用native函数库直接分配堆外内存,这样显著提高性能。