一、前言

  为什么要学习了解Java虚拟机

  1.我们需要更加清楚的了解Java底层是如何运作的,有利于我们更深刻的学习好Java。

  2.对我们调试错误提供很宝贵的经验。

  3.这是合格的Java程序必须要了解的内容。

  基于此,笔者打算出一个Java虚拟机的系列,加深自己对知识点的理解,同时也方便各位有需要的园友。

二、Java虚拟机的定义

  Java虚拟机(Java Virtual Machine),简称JVM。当我们说起Java虚拟机时,可能指的是如下三种不同的东西:

    1.抽象规范。

    2.一个具体的实现。

    3.一个运行中的虚拟机实例。

  Java虚拟机抽象规范仅仅是一个概念,在《The Java Virtual Machine Specification》中有详细的描述。该规范的实现,可能来自多个提供商,并存在于多个平台上,它或者是全部由软件实现,或者是以硬件和软件相结合的方式来实现。当运行一个Java程序的时候,也就在运行一个Java虚拟机实例。注意,我们所说的Java平台无关性是指class文件的平台无关性,JVM是和平台相关的,不同操作系统对应不同的JVM。

三、Java虚拟机的总体框架图

  下图是整个Java虚拟机的总体框架图,之后我们会经常涉及到。

四、Java虚拟机的体系结构

  下图表示了Java虚拟机的结构框图,主要描述了JVM子系统和内存区。

  

五、Java虚拟机各组成部分

  5.1 类装载子系统

  类装载子系统负责查找并装载类型,Java虚拟机由两种类装载器:启动类装载器(Java虚拟机实现的一部分)和用户自定义类装载器(Java程序的一部分)。类装载子系统负责定位和导入二进制class文件,并且保证导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用。类装载器必须严格按照如下顺序进行类的装载。

  1) 装载 -- 查找并装载类型的二进制数据

  2) 连接 -- 执行验证,准备,以及解析(可选),连接分为如下三个步骤

    验证 -- 确保被导入类型的正确性

    准备 -- 为类变量分配内存,并将其初始化为默认值

    解析 -- 把类型中的符号引用转换为直接引用

  3) 初始化 -- 把类变量初始化为正确初始值

  启动类装载器 -- Java虚拟机必须有一个启动类装载器,用于装载受信任的类,如Java API的class文件。

  用户自定义类装载器 -- 继承自ClassLoader类,ClassLoader的如下四个方法,是通往Java虚拟机的通道。

    1. protected final Class defineClass(String name, byte data[], int offset, int length);

    2. protected final Class defineClass(String name, byte data[], int offset, int length, ProtectionDomain protectionDomain);

    3. protected final Class findSystemClass(String name);

    4. protected final void resolveClass(Class c);

  这四个方法涉及到了装载和连接两个阶段,defineClass方法data参数为二进制Java Class文件格式,表示一个新的可用类型,之后把这个类型导入到方法区中。findSystemClass的参数为全限定名,通过类装载器进行装载。resolveClass参数为Class实例,完成连接初始化操作。

  5.2 方法区

  方法区是线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError。

  类信息包括1.类型全限定名。2.类型的直接超类的全限定名(除非这个类型是java.lang.Object,它没有超类)。3.类型是类类型还是接口类型。4.类型的访问修饰符(public、abstract、final的某个子集)。5.任何直接超接口的全限定名的有序列表。6.类型的常量池。7.字段信息。8.方法信息。9.除了常量以外的所有类(静态)变量。10.一个到类ClassLoader的引用。11.一个到Class类的引用。

  着重介绍常量池 -- 虚拟机必须要为每个被装载的类型维护一个常量池。常量池就是该类型所用常量的一个有序集合,包括直接常量和对其他类型、字段和方法的符号引用。它在Java程序的动态连接中起着核心作用。

  5.3 堆

  一个虚拟机实例只对应一个堆空间,堆是线程共享的。堆空间是存放对象实例的地方,几乎所有对象实例都在这里分配。堆也是垃圾收集器管理的主要区域。堆可以处于物理上不连续的内存空间中,只要逻辑上相连就行,当堆中没有足够的内存进行对象实例分配时,并且堆也无法扩展时,会抛出OutOfMemoryError异常。

  5.4 程序计数器

  每个线程拥有自己的程序计数器,线程之间的程序计数器互不影响。PC寄存器的内容总是下一条将被执行指令的"地址",这里的"地址"可以是一个本地指针,也可以是在方法字节码中相对于该方法起始指令的偏移量。如果该线程正在执行一个本地方法,则程序计数器内容为undefined,此区域在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

  5.5 Java栈

  Java栈也是线程私有的,虚拟机只会对栈进行两种操作,以帧为单位的入栈和出栈。每个方法在执行时都会创建一个帧,并入栈,成为当前帧。栈帧由三部分组成:局部变量区、操作数栈、帧数据区。

  局部变量区被组织为一个以字长为单位、从0开始计数的数组。字节码指令通过从0开始的索引来使用其中的数据。类型为int、float、reference和return Address的值在数组中只占据一项,而类型为byte、short和char的值存入时都会转化为int类型,也占一项,而long、double则连续占据两项。

  关于局部变量区给出如下一个例子。

public class Example {
public static int classMethod(int i, long l, float f, double d, Object o, byte b) {
return 0;
} public int instanceMethod(char c, double d, short s, boolean b) {
return 0;
}
}

  

  可以看到类方法的首项中没有隐含的this指针,而对象方法则会隐含this指针。并且byte,char,short,boolean类型存入局部变量区的时候都会被转化成int类型值,当被存回堆或者方法区时,才会转化回原来的类型。

  操作数栈被组织成一个以字长为单位的数组,它是通过标准的栈操作-入栈和出栈来进行访问,而不是通过索引访问。入栈和出栈也会存在类型的转化。

  栈数据区存放一些用于支持常量池解析、正常方法返回以及异常派发机制的信息。即将常量池的符号引用转化为直接地址引用、恢复发起调用的方法的帧进行正常返回,发生异常时转交异常表进行处理。

  5.6 本地方法栈

  访问本地方式时使用到的栈,为本地方法服务,本地方法区域也会抛出StackOverflowError和OutOfMemoryError异常。

  5.7 执行引擎

  用户所编写的程序如何表现正确的行为需要执行引擎的支持,执行引擎执行字节码指令,完成程序的功能。后面会详细介绍。

  5.8 本地方法接口

  本地方法接口称为JNI,是为可移植性准备的。

六、总结

  至此,虚拟机的结构就已经大体介绍完了,现在我们只需要有一个初步的了解,后面对各个部分会有更加详细的介绍。谢谢各位园友观看~

    

【JVM】JVM系列之JVM体系(一)的更多相关文章

  1. JVM基础系列第8讲:JVM 垃圾回收机制

    在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...

  2. jvm系列(八):jvm知识点总览-高级Java工程师面试必备

    在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后 ...

  3. jvm系列(四):jvm知识点总结

    原文链接:http://www.cnblogs.com/ityouknow/p/6482464.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 ...

  4. 【java虚拟机系列】java虚拟机系列之JVM总述

    我们知道java之所以能够快速崛起一个重要的原因就是其跨平台性,而跨平台就是通过java虚拟机来完成的,java虚拟机属于java底层的知识范畴,即使你不了解也不会影响绝大部分人从事的java应用层的 ...

  5. JVM基础系列第1讲:Java 语言的前世今生

    Java 语言是一门存在了 20 多年的语言,其年纪比我自己还大.虽然存在了这么长时间,但 Java 至今都是最大的工业级语言,许多大型互联网公司均采用 Java 来实现其业务系统.大到国际电商巨头阿 ...

  6. JVM规范系列开篇:为什么要读JVM规范?

    许多人知道类加载机制.JVM内存模型,但他们可能不知道什么是<Java虚拟机规范>.对于Java开发来说,<Java虚拟机规范>才是最为官方.准确的一个文档,了解这个规范可以让 ...

  7. JVM规范系列:总结

    我们花了几天的时间来阅读<Java虚拟机规范>,了解要实现一个虚拟机应该包括什么内容.通过这么一次阅读,我们大致了解了虚拟机规范的内容. 第1章.对Java虚拟机进行了一些简单的介绍. 第 ...

  8. jvm系列(八):jvm知识点总览

    在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后 ...

  9. JVM系列五:JVM监测&工具

    JVM系列五:JVM监测&工具[整理中]  http://www.cnblogs.com/redcreen/archive/2011/05/09/2040977.html 前几篇篇文章介绍了介 ...

  10. jvm系列(七):jvm调优-工具篇

    16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面,其中就包括如何利用工具来监控调优前后的性能变化.工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗 ...

随机推荐

  1. if [ "$变量1"x = "$变量2"x ]中x的含义

    问题:if [ "$变量1"x = "$变量2"x ]中x的含义是? 答:“x”字符可以为任意字符,用于防止变量为空时,某些版本的bash中会产生错误: 在一个 ...

  2. Dom的继承关系

    Document对象: 是Html文档的根节点,拥有其他的节点(element nodes, text nodes, attribute nodes, and comment nodes),并提供了获 ...

  3. XMPP iOS客户端实现二:xcode项目配置

    1.下载XMPPFramework,下载地址:https://github.com/robbiehanson/XMPPFramework 2.创建项目并将XMPP库引入: 3.添加需要的库文件: 4. ...

  4. Javascript分号,加还是不加?

    关于这个问题,网上已经有很多人讨论过了,我先说说自己对这个问题的回答:加!(但非必须) 有些人写代码,懒得加分号,除非是迫不得已才勉强放一个分号上去.如果你可以保证你写的代码不出现任何 bug,那当然 ...

  5. 在职场中混,"讲演稿"的重要性

    背景: 在职场上工作的人,思维都像流水行云一样无拘无束.某时某刻说不定就会产生点“头脑风暴”. 但是在多数情总下,只是自己想想,跟朋友吹瞌子的时候随便说说,很少有用文字,图形把自己的思维给表现出来. ...

  6. ASP.NET MVC 控制器激活(三)

    ASP.NET MVC 控制器激活(三) 前言 在上个篇幅中说到从控制器工厂的GetControllerInstance()方法来执行控制器的注入,本篇要讲是在GetControllerInstanc ...

  7. OAuth2 Backend Web Application 验证过程

    本文是从我的 github 博客转载的,原文请看. 一图胜千言.图片请自由转载,请保留图片的原始签名.

  8. Linux ls

    linux.ls linux ls命令, 我觉得是所有接触linux系统, 首先学习的命令. 这个命令, 我也早就接触过了. 只是以前是学习类型的. 学了以后, 没有做到学以致用.可惜了. 现在这篇内 ...

  9. Hadoop学习笔记——搭建

    一搭建环境列表 操作系统:centos6.5 64位 JDK环境:jdk1.7.0_71 hadoop版本:社区版本2.7.2,hadoop-2.7.2-src.tar.gz 主机名 ip 角色 用户 ...

  10. angularjs指令参数transclude

    angularjs指令参数transclude transclude翻译为嵌入,和之前看到的vue中的slots作用差不多,目的是将指令元素的子内容嵌入到指令的模板中 定义指令 <div sid ...