JVM学习笔记 – 第一章 什么是JVM?JVM基础入门和Java体系架构

  • Post author:
  • Post category:java




目录:



0.什么是JVM?

  • JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
  • 引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。

    Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,

    使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
  • Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。


打个比方,如果数学公式是Java程序,那么公式的推导过程就是JVM干的事

关系图:

在这里插入图片描述



1.学习JVM的目的

  • 面试的需要(BATJ、TMD,PKQ等面试都爱问)
  • 中高级程序员必备技能:项目管理、调优的需求
  • 追求极客的精神,比如:垃圾回收算法、JIT(即时编译器)、底层原理
  • 能够明白为什么Java最早期被称为解释型语言
  • 为了今后更好的解决线上排查问题
  • 可以通过调整JVM相关参数提高Java应用的性能
  • 可以清楚知道Java程序是如何执行的



2.Java VS C++

  • 垃圾收集机制为我们打理了很多繁琐的工作,大大提高了开发的效率,但是,垃圾收集也不是万能的,懂得JVM内部的内存结构、工作机制,是设计高扩展性应用和诊断运行时问题的基础,也是Java工程师进阶的必备能力。
  • C语言需要自己来分配内存和回收内存,Java全部交给JVM进行分配和回收。



3.Java的跨平台性

  • 每个语言都需要转换成字节码文件,最后转换的字节码文件都能通过Java虚拟机进行运行和处理。
  • 随着Java7的正式发布,Java虚拟机的设计者们通过JSR-292规范基本实现在Java虚拟机平台上运行非Java语言编写的程序。
  • Java虚拟机根本不关心运行在其内部的程序到底是使用何种编程语言编写的,它只关心“字节码”文件。也就是说Java虚拟机拥有语言无关性,并不会单纯地与Java语言“终身绑定”,只要其他编程语言的编译结果满足并包含Java虚拟机的内部指令集、符号表以及其他的辅助信息,它就是一个有效的字节码文件,就能够被虚拟机所识别并装载运行。

    在这里插入图片描述



4.字节码

  • 我们平时说的java字节码,指的是用java语言编译成的字节码。准确的说任何能在jvm平台上执行的字节码格式都是一样的。所以应该统称为:

    jvm字节码

  • 不同的编译器,可以编译出相同的字节码文件,字节码文件也可以在不同的JVM上运行。
  • Java虚拟机与Java语言并没有必然的联系,它只与特定的二进制文件格式——Class文件格式所关联,Class文件中包含了Java虚拟机指令集(或者称为字节码、Bytecodes)和符号表,还有一些其他辅助信息。

    在这里插入图片描述



5.Java生态圈

Java是目前应用最为广泛的软件开发平台之一。随着Java以及Java社区的不断壮大Java 也早已不再是简简单单的一门计算机语言了,它更是一个平台、一种文化、一个社区。

  • 作为一个平台,Java虚拟机扮演着举足轻重的作用

    • Groovy、Scala、JRuby、Kotlin等都是Java平台的一部分
  • 作为一种文化,Java几乎成为了”开源”的代名词。

    • 第三方开源软件和框架。如Tomcat、Struts,MyBatis,Spring等。
    • 就连JDK和JVM自身也有不少开源的实现,如openJDK、Harmony。
  • 作为一个社区,Java拥有全世界最多的技术拥护者和开源社区支持,有数不清的论坛和资料。从桌面应用软件、嵌入式开发到企业级应用、后台服务器、中间件,都可以看到Java的身影。其应用形式之复杂、参与人数之众多也令人咋舌。



6.虚拟机介绍



6.1虚拟机的概念

所谓虚拟机(Virtual Machine),就是一台虚拟的计算机。它是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。

  • 大名鼎鼎的Virtual Box,VMware就属于系统虚拟机,它们完全是对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台。
  • 程序虚拟机的典型代表就是

    Java虚拟机

    ,它专门为执行单个计算机程序而设计,在Java虚拟机中执行的指令我们称为Java字节码指令。
  • 无论是系统虚拟机还是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源中。



6.2Java虚拟机

  • Java虚拟机是一台执行Java字节码的虚拟计算机,它拥有独立的运行机制,其运行的Java字节码也未必由Java语言编译而成。
  • JVM平台的各种语言可以共享Java虚拟机带来的跨平台性、优秀的垃圾回器,以及可靠的即时编译器。
  • Java技术的核心就是Java虚拟机(JVM,Java Virtual Machine),因为所有的Java程序都运行在Java虚拟机内部。
  • Java虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部,解释/编译为对应平台上的机器指令执行。每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪里。


    特点:

  1. 一次编译,到处运行

  2. 自动内存管理

  3. 自动垃圾回收功能



6.3.JVM的位置

JVM是运行在操作系统之上的,它与硬件没有直接的交互

在这里插入图片描述

Java的体系结构

在这里插入图片描述



6.4 JVM的整体结构


  • HotSpot VM

    是目前市面上高性能虚拟机的代表作之一。
  • 它采用解释器与即时编译器(JIT)并存的架构。
  • 在今天,Java程序的运行性能早已脱胎换骨,已经达到了可以和C/C++程序一较高下的地步。
  • 执行引擎包含三部分:

    解释器



    即时编译器



    垃圾回收器


    在这里插入图片描述
    这个图要背下来↑



7. Java代码的执行流程

在这里插入图片描述



8. JVM架构模型

Java编译器输入的指令流基本上是一种

基于栈的指令集架构

,另外一种指令集架构则是

基于寄存器的指令集架构

。具体来说:这两种架构之间的区别:

  • 基于栈式架构的特点

    • 设计和实现更简单,适用于资源受限的系统
    • 避开了寄存器的分配难题:使用

      零地址指令方式分配
    • 指令流中的指令大部分是

      零地址指令

      ,其执行过程依赖于

      操作栈



      指令集更小,编译器容易实现
    • 不需要硬件支持,

      可移植性更好

      ,更好

      实现跨平台
  • 基于寄存器架构的特点

    • 典型的应用是x86的二进制指令集:比如传统的PC以及Android的Davlik虚拟机。
    • 指令集架构则

      完全依赖硬件

      ,与硬件的耦合度高,

      可移植性差

    • 性能优秀和执行更高效
    • 花费更少的指令去完成一项操作
    • 在大部分情况下,

      基于寄存器架构

      的指令集往往都

      以一地址指令、二地址指令和三地址指令为主

      ,而基于

      栈式架构

      的指令集却是

      以零地址指令为主



9. 两种架构的举例

同样执行2+3这种逻辑操作,其指令分别如下:

  • 基于栈的计算流程(以Java虚拟机为例)
iconst_2 //常量2入栈
istore_1
iconst_3 // 常量3入栈
istore_2
iload_1
iload_2
iadd //常量2/3出栈,执行相加
istore_0 // 结果5入栈
  • 基于寄存器的计算流程
mov eax,2 //将eax寄存器的值设为2
add eax,3 //使eax寄存器的值加3



10. 反编译字节码文件

public class StackStruTest {

    public static void main(String[] args) {
        int i = 2;
        int j = 3;
        int k = i + j;
    }

}
javap -v StackStruTest.class

在这里插入图片描述

反编译得到的指令

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_2  // 将常量 2 压入栈中
         1: istore_1  // 将常量 2 保存至变量 i 中
         2: iconst_3  // 将常量 3 压入栈中
         3: istore_2  // 将常量 3 保存至变量 j 中
         4: iload_1   // 加载变量 i
         5: iload_2   // 加载变量 j
         6: iadd      // 执行累加操作
         7: istore_3  // 加法结果保存在变量 k 中
         8: return
      LineNumberTable:
        line 10: 0
        line 11: 2
        line 12: 4
        line 13: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
            2       7     1     i   I
            4       5     2     j   I
            8       1     3     k   I
}



11. 架构总结

  • 由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令
  • 时至今日,尽管嵌入式平台已经不是Java程序的主流运行平台了(准确来说应该是HotSpot VM的宿主环境已经不局限于嵌入式平台了),那么为什么不将架构更换为基于寄存器的架构呢?
  • 因为基于栈的架构跨平台性好、指令集小,虽然相对于基于寄存器的架构来说,基于栈的架构编译得到的指令更多,执行性能也不如基于寄存器的架构好,但考虑到其跨平台性与移植性,我们还是选用栈的架构

栈:跨平台性、指令集小、指令多;执行性能比寄存器差,

以零地址指令为主

寄存器:

性能优秀和执行更高效



12. JVM的生命周期

启动–>执行–>退出

  • 虚拟机的启动

    • Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
  • 虚拟机的执行

    • 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序
    • 程序开始执行时他才运行,程序结束时他就停止

    • 执行一个所谓的Java程序的时候,真真正正在执行的是一个叫做Java虚拟机的进程
  • 虚拟机的退出

    • 程序正常执行结束
    • 程序在执行过程中遇到了异常或错误而异常终止
    • 由于操作系统用现错误而导致Java虚拟机进程终止
    • 某线程调用

      Runtime类或System类的exit( )

      方法,或

      Runtime类的halt( )

      方法,并且Java安全管理器也允许这次

      exit( )



      halt( )

      操作。
    • 除此之外,JNI(Java Native Interface)规范描述了用JNI Invocation API来加载或卸载 Java虚拟机时,Java虚拟机的退出情况。



版权声明:本文为weixin_44857327原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。