<!---->
JVM结构基础
前段时间由于研究原来广为传播的String和StringBuffer的性能问题,自己做了几个小实验并得出一些结论,但是从网友的反应来看那个研究并没有起到应有的目的,而且网友也很中肯的提出了自己的意见并对实验中的一些内容指出了其缺陷,针对他们的反应我又反编译了代码来进行对比,但是几位网友仍然不是很信服,而且上次实验的结果和反编译得到的结论并不能完全吻合,因为反编译代码的对比基本上是基于语句的多少,因此这个这个对比也确实不能使人信服,但是这给我的下一步行动指引了方向:研究JVM指令和JVM结构,在对反编译后的代码有完全的理解才能给出可能使人信服的结论。
本文以及以后将要写的一些文章就是我研究JVM规范的一些心得,我希望在和大家共同理解的基础上进行我们下一轮的深入研究。
好,闲话少说,开始我们的正文。
JVM执行的对象就是大家非常熟悉的class文件,我们也称为类文件,JVM规范定义的这个编译完成的代码文件(虽然并非强制要求是实际的文件)的格式非常的详实,但是我们这里只说一些宏观的内容,以后有机会再研究细节的内容吧。JVM要求的类文件的格式是和硬件和操作系统无关的一种二进制格式,它精确定义了类或者接口的表示,它甚至包含了字节顺序这样的细节,而字节顺序在特定平台的目标文件格式中一般都是固定的,不会进行说明。
JVM所支持的数据类型和Java语言规范中定义的几乎一样,请注意是几乎一样!也就是原始类型和引用类型,他们可以被存储在变量表中,也可以作为参数传递、被方法返回,更通常的就是成为操作的对象。为什么和Java语言规范中定义的不完全一样呢?因为JVM中有一种Java语言所没有的原始类型:返回地址类型(returnAddress type)。该类型是jsr, ret以及jsr_w指令需要使用到的,它的值是JVM指令的操作码的指针,并且它的值是不能被运行中的程序所修改的。
另外需要提到的就是布尔类型的值,虽然在Java语言中它是完全独立的值,但是在JVM中只提供了对它的有限支持,表现在: 没有单独的操作布尔类型的指令,源代码中的布尔类型的操作在编译以后是作为int类型的值进行操作的。 JVM直接支持布尔数组,newarray指令可以创建布尔数组,而它的访问和修改操作却是使用byte类型的数组的操作指令进行的:baload,bastore。(在JDK1.0,1,1以及1.2中,布尔数组被编码为byte数组,每个元素是8位) JVM用1代表true,用0代表false,编译器将源代码中的布尔类型映射为JVM中的int类型,而且必须和JVM的要求一致。
另外JVM规范中对于浮点类型的数据有大段的说明,我没有怎么看,主要是讨论JVM的浮点型和IEEE 754的关系的。
关于类型的另外一个需要提一下的是类型检查。JVM期望几乎所有的类型检查已经在运行之前完成了(通常是由编译器进行检查的)而不用JVM自己来检查。原始类型的值不需要被标记或者在运行时被检查以确定他们的类型,同样他们也不用和引用类型的值进行区分,区分工作是由JVM的指令集来完成的,JVM的指令集使用不同指令来区分它要操作的值的类型,例如iadd, ladd, fadd以及dadd是用于将两个数字相加并产生数字类型结果的所有JVM指令,但是每个指令都是针对特定类型的,分别对应int, long, float以及double。
JVM包含对对象的显式支持。类是动态分配的类实例或者是一个数组,JVM中的引用类型就是对一个对象的引用,引用类型的值可以想象为对象的指针,一个对象同时可能存在多个对它的引用,对象总是通过引用被操作、传递或者测试的。
对于引用类型,需要提及的一点就是关于null,它最初是没有运行时类型的,但是它可以被转换为任何类型,而且对于null,JVM并没有要求任何具体的值与之对应。
说完上面这些,我们就开始进入我学习JVM时最想了解的部分了,大家可要打起精神哦。 JVM为运行一个程序定义了几种数据区(Data Area),包括:pc寄存器、JVM堆栈、堆、方法区(Method Area)、运行时常量池(Runtime Constant Pool)以及本机方法堆栈(Native Method Stacks),这些数据区根据其生存期可以分为两种,一种就是和JVM的生存期相同(包括堆和方法区),一种和线程的生存期相同(其它的),和JVM生存期相同的数据区在JVM启动的时候被创建并在JVM退出的时候被销毁,而和线程生存期相同的数据区是每个线程一个的,他们在线程创建的时候被创建,在线程被销毁的时候被销毁。
由于JVM可以同时支持运行多个线程,因此每个线程必然需要各自的PC(program counter)寄存器,无论从什么角度讲,每个JVM线程只能在一个时间只能执行一个方法,该方法也就是线程的当前方法,如果该方法不是本机方法,那么PC寄存器保存的就是当前指令(JVM的指令)的地址,如果是当前方法是本机方法,PC寄存器的值就没有被定义。JVM的PC寄存器的大小足够大,可以容纳一个returnAddress类型或者特定平台的本机指针。
每个JVM线程还拥有一个私有的JVM堆栈,它存储帧(下一篇文章会讲到)。JVM堆栈和像C这样的传统编程语言中的堆栈是类似的,它保存局部变量和部分结果,并且在方法调用和返回中也担任一些职责。因为除了对帧的压入和弹出操作外,对JVM堆栈不能直接进行操作,因此帧可能是在堆上分配的。如果一个线程中计算所需的JVM堆栈大于允许的大小,JVM会抛出StackOverflowError错误,如果JVM堆栈是可以动态伸缩的,如果需要扩展,但是又没有足够的内存可用或者没有足够的内存为一个新线程创建JVM堆栈,JVM会抛出OutOfMemoryError错误。
JVM只有一个为所有线程所共享的堆,所有的类实例和数组都是在堆中创建的。堆所存储的对象被一个自动存储管理系统回收(也就是我们所熟知的垃圾收集器(gc))。对象不能被显式的释放,JVM假设没有特定类型的自动存储管理系统,存储管理技术可以根据实现者的系统需求进行选择。如果计算所需的内存堆大于自动存储管理系统可以使用的大小,JVM会抛出OutOfMemoryError错误。
JVM只有一个为所有的线程所共享的方法区,方法区类似传统语言的已编译代码的存储区或者UNIX进程的“文本”段。它存储类结构,例如运行时常量池,成员和方法数据以及方法、构造方法的代码(包括用于类和实例的初始化以及接口类型初始化的特定方法(这些特定方法以后会讲到))。虽然从逻辑上讲方法区是堆的一部分,但是JVM的简单实现可以选择不对方法区进行垃圾收集或者压缩(以笔者的理解就是类不能进行卸载)。最新版本(第二版)的JVM规范没有要求方法区的位置或者管理已编译代码的策略。如果方法区的内存不能满足一个分配请求,JVM会抛出OutOfMemoryError。
运行时常量池是类文件中的常量池表的运行时表示,它包含几种常量,范围从编译时就已知的数字常量到运行时必须进行解析的方法和成员引用。运行时常量池扮演的功能类似于传统编程语言中的符号表(symbol table),但是它所包含的数据比典型的符号表更多。 每个运行时常量池时从JVM的方法区中分配的,对于特定方法或者接口的运行时常量池是JVM在创建类或者接口的时候创建的。 当创建一个类或者接口时,如果创建运行时常量池需要的内存比方法区中的可用内容更多的内存,JVM会抛出OutOfMemoryError。 关于常量池创建的更多内容以后可能会更详细的讲解。
JVM的实现可能使用传统的堆栈(更通常的讲就是C栈)以支持本机方法(不是使用JAVA语言编写的方法),本机方法堆栈也可以用于在像C语言这样的语言中为JVM指令集实现解析器,对于不能加载本机方法以及自身不依赖传统堆栈的JVM实现而言,它可以不提供本机方法堆栈,如果提供,本机方法堆栈通常在线程创建的时候为每个线程分配(以笔者的理解应该是需要使用本机方法的线程)。如果线程计算所需的内存比本机方法堆栈所允许的大,JVM会抛出StackOverflowError错误,如果本机方法堆栈可以动态伸缩,而当需要扩展的时候又没有足够的内存时,或者没有足够的内容用于创建一个本机方法堆栈,JVM会抛出OutOfMemoryError。
对于上面的这些数据区,JVM规范允许它们的大小是固定尺寸的,也可以是根据计算的需要动态伸缩的,如果是固定尺寸的,其尺寸可以在创建时自主选择。JVM的实现可以给程序员或者用户提供控制JVM堆栈的初始大小的方法,同样,在动态伸缩的情况下可以控制最大大小和最小大小,并且它们所使用的内存空间可以不是连续的。
|
|
相关推荐
Java虚拟机(JVM)是Java程序运行的基础,它负责解释和执行字节码,管理内存,以及执行垃圾收集(Garbage Collection, GC)。在Java应用程序的开发和运行过程中,了解JVM的工作原理,监控其状态,以及进行性能调优是...
Java虚拟机(JVM)是Java程序运行的基础,它提供了平台无关性,使得Java应用程序可以在任何支持JVM的设备上运行。本资料集中包含了机构内训的JVM常见面试题,旨在帮助求职者或者开发者更好地理解和掌握JVM相关知识,...
总结来说,JVM执行子系统是Java程序运行的基础,它负责类加载、字节码执行、内存管理、垃圾回收等一系列复杂操作,为Java应用程序提供了一个高效、安全、可扩展的运行环境。理解和掌握JVM执行子系统的细节,对于优化...
【Java技术资料】-(机构内训资料)JVM和性能优化学习思维笔记是一份针对Java开发者深入理解JVM及进行性能优化的重要参考资料。这份资料可能包含了一个详细的知识地图,帮助学习者系统地掌握JVM的工作原理以及如何...
【JVM面试专题】是针对Java开发者在求职面试过程中可能会遇到的JVM相关问题的集锦,涵盖了JVM的基础知识、内存模型、垃圾收集、性能调优等多个关键领域。了解和掌握这些知识点对于成为一名优秀的Java程序员至关重要...
这份“【面试资料】-(机构内训资料)JVM常见面试题指南”很可能包含了JVM面试中经常遇到的问题和解答,帮助求职者准备面试。 1. **JVM架构** - **类加载机制**:JVM如何通过类加载器加载类,包括引导类加载器、...
Java虚拟机(JVM)是Java程序运行的基础,它负责解释和执行字节码,提供内存管理、垃圾收集以及各种优化机制。JVM性能优化是提高Java应用性能的关键环节,对于开发者来说,深入理解JVM的工作原理并进行有效优化至关...
1. **Java简介**:Java是一种跨平台的面向对象编程语言,由Sun Microsystems(现已被Oracle收购)于1995年推出。它的设计哲学是“一次编写,到处运行”,通过Java虚拟机(JVM)实现平台无关性。 2. **环境搭建**:...
在公钥基础设施(PKI)中,每个证书都有一个签发它的权威机构,即证书颁发机构(CA)。这些CA又有一个或多个上级CA,直至追溯到一个被操作系统或浏览器广泛信任的根CA。当验证证书时,系统会检查这个证书链,确保每...
这份“java基础教程多个培训机构的ppt”集合了不同培训机构的教学资源,对于初学者来说,是学习Java基础知识的理想材料。以下是对Java基础知识的一些详细讲解: 1. **Java语言概述**:Java由Sun Microsystems开发,...
这份培训机构的课件涵盖了Java的基础知识和高级应用,旨在帮助初学者全面理解并掌握Java编程。 1. **Java概述**:这部分通常会介绍Java的历史、特点、用途,以及其与C++、C#等其他语言的比较。还会涉及到JVM(Java...
《参悟Java基础核心技术》是一本专注于讲解Java编程语言核心概念和技术的电子书籍,由尚硅谷教育机构的宋红康老师编著。这本书全面覆盖了Java的基础知识,旨在帮助读者深入理解和掌握Java编程的核心要领。 Java作为...
1. **HelloWorld程序**:这是Java学习者的第一个程序,用于展示如何创建和运行一个简单的Java程序。典型的HelloWorld程序如下: ```java public class HelloWorld { public static void main(String[] args) { ...
优秀的Java培训机构应该提供从基础到高级的系统化教学,包括但不限于Java语法、面向对象编程、集合框架、多线程、网络编程、JVM原理、数据库操作、Spring框架、微服务等核心知识点。同时,与时俱进的教学内容也很...
1. **虚假宣传**:一些培训机构会夸大其词,宣称提供更多的课时、独特的教学方法或小班教学,但实际体验往往与承诺相去甚远。例如,所谓的“小班”可能非常庞大,教学质量并不如预期,而承诺的课时也可能被大幅削减...
北大青鸟作为中国知名的IT教育机构,其推出的“北大青鸟java基础ppt”无疑为初学者提供了一条系统学习Java的路径。这份PPT教程应该包含了Java语言的基础概念、语法以及常见应用,旨在帮助学习者构建坚实的编程基础。...
1. **面向对象**:Java是一种完全面向对象的语言,支持类、接口、继承、封装和多态等面向对象的特性。 2. **解释执行与编译执行**:Java代码先通过编译器编译成字节码,然后由Java虚拟机(JVM)解释执行。这使得Java...
JAVA程序可以在任何实现了JAVA虚拟机(JVM)的平台上运行,这被称为“一次编写,到处运行”的理念。 【PPT在教学中的应用】 PPT,全称PowerPoint,是Microsoft Office套件中的一个组件,用于创建和展示视觉辅助的...
1. **Java简介**:Java是由Sun Microsystems(现为Oracle Corporation的一部分)于1995年发布的面向对象的编程语言,它设计的目标是“一次编写,到处运行”。Java具有平台无关性、安全性高、可移植性强、多线程支持...
1. **Java基础**: 课程可能涵盖了Java的基本语法,包括变量、数据类型、运算符、控制结构(如if语句和循环)、类和对象、封装、继承、多态等核心概念。这些都是初学者入门Java的必备知识。 2. **面向对象编程**: ...