ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

初识 JVM(带你从不同的视角认识 JVM)

2022-01-18 15:03:02  阅读:169  来源: 互联网

标签:... 视角 01 6c 00 61 初识 JVM


初识 JVM(带你从不同的视角认识 JVM)

概述

一说到 JVM 三个字母,你脑子里首先蹦出来的是什么?我分析一般有以下三种人:

  • 第一种:JVM 三个字母,分开我是认识的,一组合,我不知道是啥
  • 第二种:他不就是 Java 虚拟机么,跑 Java 程序的
  • 第三种:分为堆内存,方法区,老年代,新生代.....巴拉巴拉...,可以跟你说几个小时的

经过我的日常观察,一般第一种人是程序猿的家属,第二种人是程序猿的同事(非 Java 工作的同事),第三种人就是程序猿本猿了,而本文的适合读者是第三种人,我试图从不同的视角出发,带领程序猿们站在另外一个高度点重新全面的重新认识一次 JVM,从浅到深的逐步深入,再一次对我们认知的 JVM 做一个全面的梳理,不仅知道它有堆内存、方法区、老年代、新生代...更要知道其原理,也要知道其使用的方法。在深入理解其设计原理的基础上,再对它进行使用和调优,就会更加的得心应手。

接下来,让我逐步带领大家进入 JVM 的世界!后续我将以 JVM 系列文章的形式,逐步带大家从浅到深的认识 JVM。

声明:以下内容篇幅较长,请耐心看完,你一定会有不一样的收获!

一切从官网开始

那么认识 JVM 的第一步该是什么呢?有很多人第一次认识 JVM 是在百度或者 google 上的,其实第一步你就错了,我认为一切应该还是从官网开始,从它出生的地方先做一个全面的了解。

Java Platform Standard Edition 8 Documentation

官网地址:docs.oracle.com/javase/8/do…

Reference -> Developer Guides -> 定位到:docs.oracle.com/javase/8/do…

Tips:花点时间,耐心的读完这段话,你会有新的心得的!

Oracle has two products that implement Java Platform Standard Edition (Java SE) 8: Java SE Development Kit (JDK) 8 and Java SE Runtime Environment (JRE) 8.

JDK 8 is a superset of JRE 8, and contains everything that is in JRE 8, plus tools such as the compilers and debuggers necessary for developing applets and applications. JRE 8 provides the libraries, the Java Virtual Machine (JVM), and other components to run applets and applications written in the Java programming language. Note that the JRE includes components not required by the Java SE specification, including both standard and non-standard Java components.

The following conceptual diagram illustrates the components of Oracle's Java SE products:

Description of Java Conceptual Diagram

Getting Started with the G1 Garbage Collector

官网地址:www.oracle.com/technetwork…

Exploring the JVM Architecture

Hotspot Architecture

The HotSpot JVM possesses an architecture that supports a strong foundation of features and capabilities and supports the ability to realize high performance and massive scalability. For example, the HotSpot JVM JIT compilers generate dynamic optimizations. In other words, they make optimization decisions while the Java application is running and generate high-performing native machine instructions targeted for the underlying system architecture. In addition, through the maturing evolution and continuous engineering of its runtime environment and multithreaded garbage collector, the HotSpot JVM yields high scalability on even the largest available computer systems.

HotSpot JVM Architecture

The main components of the JVM include the class loader, the runtime data areas, and the execution engine.

阅读理解一下(摘自上文):

原文:

In other words, they make optimization decisions while the Java application is running and generate high-performing native machine instructions targeted for the underlying system architecture

翻译:

换句话说,它能在 Java 应用程序运行时做出优化决策,并生成针对底层系统架构的高性能本地机器指令。

意思就是说,JVM 的最大能力是,针对底层不同的操作系统,将 Java 程序翻译成不同操作系统能够认识和执行的本地机器指令,提供给操作系统进行运行。

以下这个图对于认识 JVM 的人来说一点都不陌生(一次编译到处运行):

源码到类文件,再到字节码

我们先写一个最简单的 HelloWorld.java,编译一下,得到 HelloWorld.class 文件。以上两个步骤是我们每一个 Java 程序猿最清楚不过的了,一个是.java 结尾的源码文件,一个是.class 结尾的字节码文件,我们都知道一个 java 程序要想运行起来,必须经过编辑器编译成.class 字节码文件,JVM 才可以运行起来。但是你有没有想过,这个.class 结尾的字节码文件是如何运行起来,并且在控制台上打印出“Hello World”的呢?

别急,通过以下几个步骤的解读,让我带领大家进入 JVM 的世界,从不同的角度来重新认识一次 JVM。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
复制代码

查看一个 class 文件字节码

我们先通过 JDK 自带的命令:hexdump -C HelloWorld.class 来查看下字节码。

输入以上命令后,输出以下内容,现在这一堆东西,你一定看不懂,不急,先看下官网是怎么说的,看下面内容。

00000000  ca fe ba be 00 00 00 34  00 22 0a 00 06 00 14 09  |.......4."......|
00000010  00 15 00 16 08 00 17 0a  00 18 00 19 07 00 1a 07  |................|
00000020  00 1b 01 00 06 3c 69 6e  69 74 3e 01 00 03 28 29  |.....<init>...()|
00000030  56 01 00 04 43 6f 64 65  01 00 0f 4c 69 6e 65 4e  |V...Code...LineN|
00000040  75 6d 62 65 72 54 61 62  6c 65 01 00 12 4c 6f 63  |umberTable...Loc|
00000050  61 6c 56 61 72 69 61 62  6c 65 54 61 62 6c 65 01  |alVariableTable.|
00000060  00 04 74 68 69 73 01 00  0c 4c 48 65 6c 6c 6f 57  |..this...LHelloW|
00000070  6f 72 6c 64 3b 01 00 04  6d 61 69 6e 01 00 16 28  |orld;...main...(|
00000080  5b 4c 6a 61 76 61 2f 6c  61 6e 67 2f 53 74 72 69  |[Ljava/lang/Stri|
00000090  6e 67 3b 29 56 01 00 04  61 72 67 73 01 00 13 5b  |ng;)V...args...[|
000000a0  4c 6a 61 76 61 2f 6c 61  6e 67 2f 53 74 72 69 6e  |Ljava/lang/Strin|
000000b0  67 3b 01 00 0a 53 6f 75  72 63 65 46 69 6c 65 01  |g;...SourceFile.|
000000c0  00 0f 48 65 6c 6c 6f 57  6f 72 6c 64 2e 6a 61 76  |..HelloWorld.jav|
000000d0  61 0c 00 07 00 08 07 00  1c 0c 00 1d 00 1e 01 00  |a...............|
000000e0  0b 68 65 6c 6c 6f 20 77  6f 72 6c 64 07 00 1f 0c  |.hello world....|
000000f0  00 20 00 21 01 00 0a 48  65 6c 6c 6f 57 6f 72 6c  |. .!...HelloWorl|
00000100  64 01 00 10 6a 61 76 61  2f 6c 61 6e 67 2f 4f 62  |d...java/lang/Ob|
00000110  6a 65 63 74 01 00 10 6a  61 76 61 2f 6c 61 6e 67  |ject...java/lang|
00000120  2f 53 79 73 74 65 6d 01  00 03 6f 75 74 01 00 15  |/System...out...|
00000130  4c 6a 61 76 61 2f 69 6f  2f 50 72 69 6e 74 53 74  |Ljava/io/PrintSt|
00000140  72 65 61 6d 3b 01 00 13  6a 61 76 61 2f 69 6f 2f  |ream;...java/io/|
00000150  50 72 69 6e 74 53 74 72  65 61 6d 01 00 07 70 72  |PrintStream...pr|
00000160  69 6e 74 6c 6e 01 00 15  28 4c 6a 61 76 61 2f 6c  |intln...(Ljava/l|
00000170  61 6e 67 2f 53 74 72 69  6e 67 3b 29 56 00 21 00  |ang/String;)V.!.|
00000180  05 00 06 00 00 00 00 00  02 00 01 00 07 00 08 00  |................|
00000190  01 00 09 00 00 00 2f 00  01 00 01 00 00 00 05 2a  |....../........*|
000001a0  b7 00 01 b1 00 00 00 02  00 0a 00 00 00 06 00 01  |................|
000001b0  00 00 00 06 00 0b 00 00  00 0c 00 01 00 00 00 05  |................|
000001c0  00 0c 00 0d 00 00 00 09  00 0e 00 0f 00 01 00 09  |................|
000001d0  00 00 00 37 00 02 00 01  00 00 00 09 b2 00 02 12  |...7............|
000001e0  03 b6 00 04 b1 00 00 00  02 00 0a 00 00 00 0a 00  |................|
000001f0  02 00 00 00 08 00 08 00  09 00 0b 00 00 00 0c 00  |................|
00000200  01 00 00 00 09 00 10 00  11 00 00 00 01 00 12 00  |................|
00000210  00 00 02 00 13                                    |.....|
00000215
复制代码

The ClassFile Structure(字节码解析)

看看官网是如何解释字节码文件的:

官网地址:docs.oracle.com/javase/spec…

A class file consists of a single ClassFile structure:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
复制代码

解读字节码文件

第一个,u4 magic;

  • u4:代表 4个字节 Byte(0x cafebabe),他是个魔数(不具有业务含义,只是表明了该文件的类型)

基础知识:

一个字节存储 8位无符号数,储存的数值范围为 0-255。1111 0000(为 1个字节)

1Byte = 8bit

1Byte = 2 位16 进制

4Byte = 0x cafebabe

所以,u4 magic,就是 0x cafebabe,转换为二进制为:1100 1010 1111 1110 1011 1010 1011 1110

cafebabe

第二个和第三个 ,u2 minor_version; u2 major_version; (合并组合为版本号)

  • u2 minor_version:代表 2个字节(0x 00 00),代表小版本号
  • u2 major_version:代表 2个字节(0x 00 34),代表主版本号
  • 主版本号+小版本号合并起来,组成版本号,0x 00000034 -->转换成十进制就是:52(查找对应表,表示版本号为:Java SE8)

版本号对应表

第四个,u2 constant_pool_count; 表示常量数量

constant_pool_count

The value of the constant_pool_count item is equal to the number of entries in the constant_pool table plus one. A constant_pool index is considered valid if it is greater than zero and less than constant_pool_count, with the exception for constants of type long and double noted in §4.4.5.

  • u2 constant_pool_count:代表 2个字节(0x 00 22),转换十进制值为:34,代表常量池中,常量的数量有 34-1=33 个
  • 那么这个类里面到底有哪些常量呢? 看下面的常量数组:

第五个,cp_info constant_pool[constant_pool_count-1]; 表示常量数组

constant_pool[]

The constant_pool is a table of structures (§4.4) representing various string constants, class and interface names, field names, and other constants that are referred to within the ClassFile structure and its substructures. The format of each constant_pool table entry is indicated by its first "tag" byte.

The constant_pool table is indexed from 1 to constant_pool_count - 1.

  • 每个常量的形式:

The Constant Pool

Java Virtual Machine instructions do not rely on the run-time layout of classes, interfaces, class instances, or arrays. Instead, instructions refer to symbolic information in the constant_pool table.

All constant_pool table entries have the following general format:

cp_info {
    u1 tag;      //表示:常量的类型
    u1 info[];   //表示:
}
复制代码

第一个常量:

  • u1 tag:代表 1个字节(0x 0a),转换为十进制值为:10,找到以下对应表,表示是一个方法类型的常量
// 方法类型常量
CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
复制代码
常量编号u1 tag常量类型常量内容
#10x 0a-->10CONSTANT_Methodrefu2 class_index:0x 00 06--> #6
u2 name_and_type_index:0x 00 14 --> #20
#6.#20

常量类型对应表

其他常量解析:(按照上面的方法,一步一步,就可以解析出来这样一张表格)

到现在为止,你一定还是看不懂解析出这一堆有啥用,不着急,先看下面的一个命令。

常量编号u1 tag常量类型常量内容
#10x 0a-->10CONSTANT_Methodrefu2 class_index:0x 00 06--> #6
u2 name_and_type_index:0x 00 14 --> #20
#6.#20
#20x 09-->9CONSTANT_Fieldrefu2 class_index:0x 00 15--> #21
u2 name_and_type_index:0x 00 16-> #22
#21.#22
#30x 08-->8CONSTANT_Stringu2 string_index:0x 00 17--> #23
#40x 0a-->10CONSTANT_Methodrefu2 class_index:0x 00 18--> #24
u2 name_and_type_index:0x 00 19 --> #25
#24.#25
...
#33

javap 反汇编

  • 命令:javap -v -p -c HelloWorld.class > HelloWorld_javap.txt (将 HelloWorld 字节码文件进行反汇编,生成的内容写入 HelloWorld_javap.txt)
// 截取部分内容如下:
Classfile /.../HelloWorld.class
  Last modified 2021-9-28; size 533 bytes
  MD5 checksum c3ef731e76bb9c516e7840a04a0c71af           //<-----------magic
  Compiled from "HelloWorld.java"
public class HelloWorld
  minor version: 0
  major version: 52                       //<-----------------版本号
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #23            // hello world
   #4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #26            // HelloWorld
   #6 = Class              #27            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
   ...
   #33
   ...
复制代码

小结

从上面我们的分析,我们大概知道了一个 Java 源文件需要首先编译成 class 文件后,JVM 虚拟机才能真正的运行这段代码的一个全过程,那么接下来,我们要研究下,class 文件是如何被加载到 JVM 的,Java 类加载机制。

标签:...,视角,01,6c,00,61,初识,JVM
来源: https://blog.csdn.net/SharingOfficer/article/details/122560082

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有