博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Java学习指南》—— 1.2 虚拟机
阅读量:7009 次
发布时间:2019-06-28

本文共 2434 字,大约阅读时间需要 8 分钟。

本节书摘来异步社区《Java学习指南》一书中的第1章,第1.2节,作者:【美】Patrick Niemeyer , Daniel Leuck,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.2 虚拟机

Java既是一种编译语言也是一种解释语言。Java源代码将被转换为简单的二进制指令,这与通常的微处理器机器码非常类似。不过,C或C++ 源代码要针对特定处理器模型而优化为本地指令,而Java源代码却均会编译为一种通用格式,即面向虚拟机的指令。

已编译Java字节码由一个Java运行时解释器执行。运行时系统可以完成一个实际处理器所做的所有正常操作,但是会在一个安全的虚拟环境中完成这些工作。它会执行一个基于栈的指令集,并像操作系统一样管理内存。运行时系统将创建并操作基本(primitive)数据类型,另外加载和调用新近引用的代码块。最重要的是,所有这些都是遵循一个严格定义的开放规范完成的,任何人如若希望生成一个与Java兼容的虚拟机,都可实施此规范。综合来看,虚拟机和语言定义则提供了一个完整的规范。这样,基本Java语言的所有特性都得到了义,而且与实现无关。例如,Java指定了所有基本数据类型的大小,而不是将其留待平台实现来确定。

Java解释器是相对轻量级的,而且规模较小,它可以实现为某种特定平台所需的任何一种形式。解释器可以作为一个单独的应用运行,也可以嵌入到另一个软件中(如Web浏览器)。综合起来看,这意味着Java代码隐含的就是可移植的。同样的Java应用程序的字节码,可以运行在提供了Java运行时环境的任何平台上,如图1-1所示。你不需要为了不同的平台而提供应用程序的其他版本,并且你不必把源代码分发给用户。

92bd719c11ea87f0c57fc1ab2e67d2fd04a0fa09

Java代码的基本单位是类。与其他面向对象语言类似,类是包含可执行代码和数据的应用组件。已编译的Java类采用一种通用的二进制格式发布,其中包含有Java字节码和其他类信息。类可以分散地加以维护,并保存于本地的文件或归档文件中,也可以保存在网络服务器上。应用需要类时,将在运行时动态地进行定位和加载。

除了特定于平台的运行时系统外,Java还有大量的基本类,其中包含有依赖于架构的方法。这些本地方法(native method)相当于Java虚拟机和真实世界之间的网关。它们在主机平台上以一种本地编译语言实现,并提供对网络、窗口系统和主机文件系统等资源的低层级访问。然而,Java的主要部分则完全用Java编写的,都是从这些基本部分演化而来,因此是可移植的。这包括基本Java工具,如Java编译器、网络和GUI库,它们都采用Java编写,因此在所有Java平台上均可以下同的方式使用而不需要移植。

基于历史的原因,往往认为解释器很慢,但是由于Java并非传统的解释语言。除了将源代码编译为可移植的字节码,Java还得到了精心的设计,通过将字节码动态编译为本地机器码,使得运行时系统的软件实现可以对其性能进行优化。这也称为即时(Just-In-Time,JIT)编译或动态编译。利用JIT编译,Java代码可以与本地已编译代码执行得一样快,同时还可保持其可传输性和安全性。

对于力图比较语言性能的人来说,这往往是一个误区。已编译Java代码只是由于安全性和虚拟机设计(数组越界检查)而导致运行时性能有所下降,而这也是性能下降的唯一的内在因素。而其他的所有内容都可以优化为本地码,这一点与静态编译语言所能做的并无二致。除此之外,较之于其他语言,Java语言还包括了更多的结构化信息,这样就为优化提供了更大的空间。还要记住,这些优化可以在运行时完成,即可以考虑到实际的应用特性。那么什么工作更适合于在编译时完成而不是运行时完成呢?在此有一个权衡,即时间。

传统JIT编译的问题在于,优化代码会花费时间。因此,JIT编译器可以得到很好的结果,但是,在应用程序启动的时候会有显著的延迟。对于长时间运行的服务器端应用程序来说,这通常不是个问题,而对于在计算能力有限的较小设备上运行的客户端软件和应用程序来说,这却是一个严重的问题。为了解决这个问题,Java的编译器技术(称为HotSpot)使用了一种叫做自适应编译(adaptive compilation)的技巧。如果仔细查看程序究竟花费时间做了哪些工作,可以发现它们往往会把绝大部分时间用于反复执行一部分代码。这一反复执行的代码块可能仅仅是整个程序中很小的一部分,但是其表现却决定了整个程序的性能。自适应编译还允许Java运行时利用一些新的类型的优化,而这些优化在一种静态编译型语言中是无法做到的,因此,Java代码号称在某些情况下可以比C/C++运行得更快。

为了充分利用这一事实,HotSpot仍以一个正常的Java字节码解释器“出场”,但在此存在一个区别:它在执行代码时要对代码进行测量(探查),从而查看哪些部分得到了重复执行。一旦获知对于性能有关键影响的代码部分,HotSpot将把这些代码段编译为真正的机器码。由于它只是将程序的一小部分编译为机器码,因此就有足够的时间对这一部分加以优化。程序余下的部分则根本无需编译,只要进行解释即可,这样可以节省内存和时间。实际上,Java VM(虚拟机)可以以两种模式运行:客户端和服务器,这分别决定了重点究竟是快速的启动时间以及节省内存还是最佳的性能。

此时,一个自然而然的问题是,为何每次一个应用程序关闭的时候,要丢弃这些很好的探查信息?Sun在发布Java 5.0的时候,将共享的、只读的类持久地存储到一个优化后的表单中,从而部分地回答了这个问题。这显著地减少了启动时间,以及在一台给定的机器上运行多个Java应用程序的负担。实现这一点的技术很复杂,但是,思路很简单:即优化程序中需要快速运行的部分,而不需要担心其他的部分。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

你可能感兴趣的文章
DORIS-软件网址
查看>>
单例模式
查看>>
SICP 习题 (1.10)解题总结
查看>>
Windows 下OpenSSL 安装
查看>>
SpringBoot整合Kotlin构建Web服务
查看>>
基于Mixin Network的PHP比特币开发教程 之一:创建机器人
查看>>
区块链是一个公共数据库,要放在一个块内
查看>>
vuex实现及简略解析
查看>>
Docker 使用 supervisord 管理 lumen队列与crontab
查看>>
vue-router源码解析(二)插件实现
查看>>
危险 AI 花名册
查看>>
日常工作-处理Windows下PHPStudy中的Apache无法启动的解决方法
查看>>
Windows Server已可安装Docker,Azure开始支持Mesosphere
查看>>
React从入门到精通系列之(15)不可控组件
查看>>
与Susan Fowler探讨生产就绪微服务之问答
查看>>
JCP EC投票反对Java平台模块系统
查看>>
Liftbridge为NATS提供了类Kafka的日志API
查看>>
Realm为Node.js发布对象数据库
查看>>
[译] 如何运用新技术提升网页速度和性能
查看>>
全域赋能和智慧全球,阿里巴巴大数据技术前瞻与案例
查看>>