【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你认识和了解Java虚拟机的特性和本质

发布时间:2024年01月11日

专栏介绍

学习JVM需要一定的编程经验和计算机基础知识,适用于从事Java开发、系统架构设计、性能优化、研究学习等领域的专业人士和技术爱好者。

前提准备

  • 编程基础:具备良好的编程基础,理解面向对象编程(OOP)的基本概念,熟悉Java编程语言。
  • 数据结构与算法:对基本的数据结构和算法有一定了解,理解内存管理、线程操作等基本概念。

面向人群

学习本专栏以及本章内容的前提和适用人群如下:

  • Java开发人员:JVM是Java程序的核心执行引擎,因此Java开发人员需要深入了解JVM的工作原理和运行机制,以优化程序性能并解决相关问题。
  • 系统架构师和高级工程师:对系统整体性能、稳定性有较高要求的人群,有必要深入理解JVM以优化系统性能。
  • Java程序员和技术爱好者:具备一定Java编程经验,有意向深入了解JVM内部工作原理的人群。
  • 研究人员和学生:从事计算机科学相关研究或学习的人群,有兴趣深入研究JVM内部原理和优化方法。
  • JVM运维工程师:负责JVM性能优化、故障排查和调优的专业人员,需要对JVM有深入的理解。

知识脉络

每位Java开发者都了解到Java字节码是在Java运行时环境(JRE)上执行的。JRE包含了最为关键的组成部分:Java虚拟机(JVM),它负责分析和执行Java字节码。通常情况下,大多数Java开发者无需深入了解虚拟机的内部运行原理。即使对虚拟机的运行机制不甚了解,也不会对开发工作产生太多影响。然而,对JVM有一定了解的话,将更有助于深入理解Java语言,并解决一些看似困难的问题。

本专栏全面系统地剖析了特定虚拟机产品(即HotSpot,Oracle官方虚拟机)的实现,本人不仅深刻地讲解了看似深奥的原理,还提供了大量易于上手的实践案例,下面是总体的JVM相关的知识拓扑架构。

在这里插入图片描述

tips:当然还有一些最新的JVM特性未在这张图并非展示本专栏的全部内容,另外还包含了最新的JVM特性。

背景介绍

Java虚拟机被称为“虚拟”的原因在于它是由一个规范定义的抽象计算机。因此,要运行Java程序,需要一个符合该规范的具体实现。本文主要描述了这个规范本身,同时也针对某些特性做了更细致的描述,包括它们可能的实现方式。

Java虚拟机定义

理解Java虚拟机时,首先需要认识到“Java虚拟机”可能代表以下两种不同的概念:

抽象规范

  • Java虚拟机规范定义了Java虚拟机的行为表现。
  • 不同的实现例如HotSpot、J9、JRockit需要遵循JVM规范,但具体实现方式并不需要与规范中的Java虚拟机完全一致。

多种平台实现

Java虚拟机能够执行符合规范的Class文件,并不仅限于执行Java程序,也支持其他编程语言,比如Scala、Clojure、Groovy、Fantom、Fortress、Nice、Jpython、JRuby、Rhino、Ioke、Jaskell,甚至还包括一些传统的编程语言如C、Fortran。

JVM和JRE、JDK的关系

在这里插入图片描述

  • JVM是Java Virtual Machine的缩写,用于执行符合规范的Class文件。
  • JRE指的是Java Runtime Environment,其中包含了JVM和类库。
  • JDK则是Java Development Kit的缩写,包含了JRE和一些开发工具,比如javac。

JVM实例和JVM执行引擎实例

JVM实例对应着独立运行的Java程序,而JVM执行引擎实例则对应着用户运行程序的线程;换句话说,JVM实例对应着进程级别,而执行引擎对应着线程级别。

在这里插入图片描述

JVM的基本结构

在Java虚拟机规范中,一个虚拟机实例的行为是按照子系统、内存区、数据类型以及指令等术语来描述的。这些组成部分共同展示了抽象的虚拟机内部抽象体系结构。然而,规范中对它们的定义并非是为了强制规定Java虚拟机实现内部的体系结构,而更多地是为了严格地定义这些实现的外部特征。规范本身通过定义这些抽象的组成部分以及它们之间的交互,来界定任何Java虚拟机实现都必须遵守的行为。

在这里插入图片描述
每个Java虚拟机都包括类加载器子系统,它根据给定的全限定名来加载类型(类或接口)。同样,每个Java虚拟机也包含执行引擎,它负责执行被加载类中的方法的指令。

类加载子系统

类加载子系统的功能是根据给定的全限定名类名(比如:java.lang.Object)将class文件加载到Runtime data area中的method area。开发者可以通过继承java.lang.ClassLoader类来实现自定义的Class loader。

JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:
在这里插入图片描述

Bootstrap ClassLoader

Bootstrap ClassLoader负责将$JAVA_HOME/jre/lib目录下的所有类库加载到内存中。Bootstrap类加载器属于JVM级别,由C++实现,不是ClassLoader的子类,开发者也无法直接获取其实例。

启动类加载器的引用,所以不允许直接通过引用进行操作。

Extension ClassLoader

Extension ClassLoader负责加载Java平台中的一些扩展功能的jar包,由sun.misc.Launcher$ExtClassLoader实现,它是一个Java类,继承自URLClassLoader超类。Extension ClassLoader负责将%JRE_HOME/lib/ext目录下的jar和class加载到内存中,开发者可以直接使用该加载器。

在这里插入图片描述

App ClassLoader

App ClassLoader负责将环境变量classpath中指定的jar包和目录中的class加载到内存中,开发者可以直接使用系统类加载器。

在这里插入图片描述

Custom ClassLoader

Custom ClassLoader是应用程序根据自身需求定制的ClassLoader(通常是java.lang.ClassLoader的子类)。它可以在程序运行时动态加载class文件,体现了Java的动态实时类加载特性。例如,像tomcat、jboss这样的应用会根据J2EE规范自行实现ClassLoader。

在这里插入图片描述
在某些应用场景中,自定义ClassLoader仍然是非常适用的,特别是需要灵活动态加载class的情况下。

内存空间

JVM包括两个子系统和两个组件:class loader(类加载器)、Execution engine(执行引擎);以及两个组件:Runtime data area(运行时数据区)、Native interface(本地接口)。
在这里插入图片描述

执行引擎(Execution engine)

执行引擎的功能是执行classes中的指令。任何JVM规范实现(比如JDK)的核心都包括Execution engine,不同的JDK,比如Sun的JDK和IBM的JDK,其性能优劣主要取决于它们各自实现的Execution engine的好坏。

Native interface组件

native libraries交互是Java与其他编程语言进行交互的接口。当调用native方法时,程序进入一个全新且不再受虚拟机限制的领域,因此可能出现JVM无法控制的native heap OutOfMemory错误。

Runtime Data Area(运行时数据区)

运行时数据区是我们常说的JVM的内存,主要分为五个部分:

在这里插入图片描述

  1. Heap (堆):每个Java虚拟机实例中只存在一个堆空间。
  2. Method Area (方法区域):方法区域存储了被装载的class的信息。当虚拟机装载某个类型时,它使用类加载器定位相应的class文件,然后读入这个class文件内容并传输到虚拟机中。
  3. Java Stack (Java的栈):虚拟机只会对Java栈进行两种直接操作:以帧为单位的压栈或出栈。
  4. Program Counter (程序计数器):每个线程都有自己的程序计数器,该寄存器是线程启动时创建的。程序计数器的内容始终指向下一条将被执行的指令的地址,该地址可以是本地指针,也可以是方法区中相对应于该方法起始指令的偏移量。
  5. Native method stack (本地方法栈):保存native方法进入区域的地址。

内存共享和非共享

Heap和Method Area是所有线程共享使用的,而Java Stack、Program Counter和Native Method Stack是以线程为粒度的,每个线程拥有独立的部分。

未完待续

由于篇幅过长,因此暂时写到这里,后续内容会在后面的文章中继续体现和分析,下一篇文章会针对于JVM体系的细节进行深入分析和探索。

文章来源:https://blog.csdn.net/l569590478/article/details/135526641
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。