• 第一篇章:JVM与Java体系结构


    JVM与Java体系结构

    本专栏学习内容来自尚硅谷宋红康老师的视频以及《深入理解JVM虚拟机》第三版

    有兴趣的小伙伴可以点击视频地址观看,也可以点击下载电子书

    虚拟机与Java虚拟机

    虚拟机(Virtual Machine)

    • 对于程序员来说,虚拟机并不陌生,所谓虚拟机就是一台虚拟的计算机。它是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。
      • 大名鼎鼎的Visual Box,VMware就属于系统虚拟机,它们完全是对物理计算机的仿真,提供一个可运行完整操作系统的软件平台。小黄曾经在VMware中安装过CentOS,可以通过界面对其进行物理计算机的操作
      • 程序虚拟机的典型代表就是Java虚拟机,它专门为执行单个计算机程序而设计,在Java虚拟机中执行的指令我们成为Java字节码指令
    • 无论是系统虚拟机还是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源中

    Java虚拟机(JVM,Java Virtual Machine)

    从某些程度上来讲,Java虚拟机是比Java语言更成功的软件,这真正的让Java语言实现了一次编译,到处运行

    • Java虚拟机时一台执行Java字节码的虚拟机,它拥有独立的运行机制,其运行的Java字节码文件未必是由Java语言编译的
    • JVM平台的各种语言可以共享Java虚拟机带来的跨平台性、优秀的垃圾回收期,以及可靠的即时编译器
    • Java技术的核心就是Java虚拟机,因为所有的Java程序都运行在Java虚拟机内部

    JVM的位置

    下图描述了JVM所处的位置,熟悉Java的小伙伴都知道,.java文件通过编译成,class文件,也就是我们所说的字节码文件,而JVM对字节码文件进行一些列的操作转换成各个操作系统所能看懂的汇编语言,从而执行命令。

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

    JVM所处位置

    在面试中经常被问到JDK,JRE两者有什么区别

    如果单单想要运行Java程序,只需要安装JRE即可,而从事Java开发必须要安装JDK,JDK可以把编写的.java文件编译成JVM可以读懂的.class文件

    在这里插入图片描述

    JVM的整体结构

    下图是JVM的整体结构,之后学习的路线就会按照下图来一步步学习

    这里主要提一下执行引擎,Java文件到被系统执行一共经历了两次编译

    第一次就是前面说的前端编译器,将.java文件编译成.class文件,因为JVM所能读懂的只有.class文件。

    第二次在执行引擎中,无论是Java、c、python都属于高级语言,计算机操作系统是无法识别该语言的,而执行引擎可以将.class文件编译成计算机能识别的语言(汇编语言)

    另外在运行时数据区中,标红的两块(方法区和堆)中的东西多线程时共享的

    请添加图片描述

    栈的指令集架构和寄存器的指令集架构

    Java编译器输入的指令流基本上是一种基于栈的指令集架构,另外一种指令集架构则是基于寄存器的指令集架构

    基于栈的指令集架构的特点

    • 设计和实现更简单,适用于资源受限的系统
    • 避开了寄存器的分配难题:使用零地址指令方式分配
    • 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器容易实现
    • 不需要硬件支持,可以移植性更好,更好实现跨平台

    基于寄存器的指令集架构的特点

    • 典型的应用是x86的二进制指令集:比如传统的pc以及安卓的Davlik虚拟机
    • 指令集架构则完全依赖硬件,可移植性差
    • 性能优秀,执行更高效
    • 花费更少的指令去完成一项操作
    • 在大部分轻快下,基于寄存器架构的指令集往往都是以一地址指令、二地址指令和三地址指令为主,二基于栈架构的指令集却是以零地址指令为主

    体验栈的指令集架构

    一段比较简单的程序

    public class StackTest {
        public static void main(String[] args) {
            int i = 2;
            int j = 3;
            int m = i + j;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    编译之后,我们通过反编译查看class文件

    # 指令
     javap -v .\StackTest.class
    # 结果
    stack=2, locals=4, args_size=1
        0: iconst_2 #生成常量2
        1: istore_1 #保存在索引为1的位置
        2: iconst_3 #生成常量3
        3: istore_2 #保存在索引为2的位置
        4: iload_1 #加载第一个位置的值
        5: iload_2 #加载第二个位置的值
        6: iadd #相加
        7: istore_3 #将结果保存在索引为3的位置
        8: return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    JVM的生命周期

    虚拟机的启动

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

    虚拟机的执行

    • 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序
    • 程序开始执行时他才运行,程序结束时他就停止
    • 执行一个所谓的Java程序的时候,真真正正在执行的是一个叫做Java虚拟机的进程

    在上述程序中添加一个睡眠任务,方便我们观察Java虚拟机的进程

    public class StackTest {
        public static void main(String[] args) {
            int i = 2;
            int j = 3;
            int m = i + j;
    
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    通过jps指令,可以查看Java虚拟机中的进程,我们可以看到在运行中时会多一个StackTest的进程

    # 程序运行中
    PS D:\Desktop\Study\JVM\jvm\practice1\target\classes\com\example\practice1> jps
    10400 StackTest #虚拟机的进程
    12448
    17696 Launcher
    9648 RemoteMavenServer36
    16676 RemoteMavenServer36
    10108 Jps
    15276 RemoteMavenServer36
    # 程序运行结束
    PS D:\Desktop\Study\JVM\jvm\practice1\target\classes\com\example\practice1> jps
    12448
    17696 Launcher
    9648 RemoteMavenServer36
    16676 RemoteMavenServer36
    15276 RemoteMavenServer36
    8124 Jps
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    虚拟机的退出

    • 程序正常执行结束
    • 程序在执行过程中遇到了异常或错误而异常终止
    • 由于操作系统出现错误而导致Java虚拟机进程终止
    • 某线程调用Runtime类或System类的exit方法,或Runtime类的halt方法,并且Java安全管理器也允许这次exit或halt操作

    System类的exit方法,实际上调用了Runtime类的exit方法

    在这里插入图片描述

    而无论是Runtime类中的exit方法还是halt方法,最终都会调用Shutdown类中的halt方法对线程进行种植

    在这里插入图片描述

  • 相关阅读:
    剑指 Offer 33. 二叉搜索树的后序遍历序列
    由浅入深,从掌握Promise的基本使用到手写Promise
    Elasticsearch--easy-ES框架使用,轻松操作查询Elasticsearch,简化开发
    oracle mysql索引区别
    【贪心算法-LeetCode3:无重复字符的最长子串(Java实现)】
    【日更】 代理
    cadence SPB17.4 S032 - Update Symbols失败的问题
    FastAPI 学习之路(一)fastapi--高性能web开发框架
    查看docker 容器的端口
    Antd pro中ProFormSelect使用initialValues
  • 原文地址:https://blog.csdn.net/Yellow_Star___/article/details/125561463