本节主要讲的是运行时数据区,也就是下图这部分,它是在类加载完成后的阶段

当我们通过前面的:类的加载 –> 验证 –> 准备 –> 解析 –> 初始化,这几个阶段完成后,就会用到执行引擎对我们的类进行使用,同时执行引擎将会使用到我们运行时数据区
类比一下也就是大厨做饭,我们把大厨后面的东西(切好的菜,刀,调料),比作是运行时数据区。而厨师可以类比于执行引擎,将通过准备的东西进行制作成精美的菜品。

内存是非常重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策略,保证了JVM的高效稳定运行。不同的JVM对于内存的划分方式和管理机制存在着部分差异。结合JVM虚拟机规范,来探讨一下经典的JVM内存布局。
我们通过磁盘或者网络IO得到的数据,都需要先加载到内存中,然后CPU从内存中获取数据进行读取,也就是说内存充当了CPU和磁盘之间的桥梁
Java虚拟机定义了若干种程序运行期间会使用到的运行时数据区:其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。
灰色的为单独线程私有的,红色的为多个线程共享的。即:

每个JVM只有一个Runtime实例。即为运行时环境,相当于内存结构的中间的那个框框:运行时环境。
如果你使用jconsole或者是任何一个调试工具,都能看到在后台有许多线程在运行。这些后台线程不包括调用public static void main(String[])的main线程以及所有这个main线程自己创建的线程。
这些主要的后台系统线程在Hotspot JVM里主要是以下几个:
官方文档网址:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

PC寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码。由执行引擎读取下一条指令,并执行该指令。

public class PCRegisterTest { public static void main(String[] args) { int i = 10; int j = 20; int k = i + j; String s = "abc"; System.out.println(i); System.out.println(k); }}查看字节码
看字节码的方法:https://blog.csdn.net/21aspnet/article/details/88351875
Classfile /F:/IDEAWorkSpaceSourceCode/JVMDemo/out/production/chapter04/com/atguigu/java/PCRegisterTest.class Last modified 2020-11-2; size 675 bytes MD5 checksum 53b3ef104479ec9e9b7ce5319e5881d3 Compiled from "PCRegisterTest.java"public class com.atguigu.java.PCRegisterTest minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPERConstant pool: #1 = Methodref #6.#26 // java/lang/Object."<init>":()V #2 = String #27 // abc #3 = Fieldref #28.#29 // java/lang/System.out:Ljava/io/PrintStream; #4 = Methodref #30.#31 // java/io/PrintStream.println:(I)V #5 = Class #32 // com/atguigu/java/PCRegisterTest #6 = Class #33 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/atguigu/java/PCRegisterTest; #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = Utf8 args #17 = Utf8 [Ljava/lang/String; #18 = Utf8 i #19 = Utf8 I #20 = Utf8 j #21 = Utf8 k #22 = Utf8 s #23 = Utf8 Ljava/lang/String; #24 = Utf8 SourceFile #25 = Utf8 PCRegisterTest.java #26 = NameAndType #7:#8 // "<init>":()V #27 = Utf8 abc #28 = Class #34 // java/lang/System #29 = NameAndType #35:#36 // out:Ljava/io/PrintStream; #30 = Class #37 // java/io/PrintStream #31 = NameAndType #38:#39 // println:(I)V #32 = Utf8 com/atguigu/java/PCRegisterTest #33 = Utf8 java/lang/Object #34 = Utf8 java/lang/System #35 = Utf8 out #36 = Utf8 Ljava/io/PrintStream; #37 = Utf8 java/io/PrintStream #38 = Utf8 println #39 = Utf8 (I)V{ public com.atguigu.java.PCRegisterTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/atguigu/java/PCRegisterTest; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=5, args_size=1 0: bipush 10 2: istore_1 3: bipush 20 5: istore_2 6: iload_1 7: iload_2 8: iadd 9: istore_3 10: ldc #2 // String abc 12: astore 4 14: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 17: iload_1 18: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 21: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 24: iload_3 25: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 28: return LineNumberTable: line 10: 0 line 11: 3 line 12: 6 line 14: 10 line 15: 14 line 16: 21 line 18: 28 LocalVariableTable: Start Length Slot Name Signature 0 29 0 args [Ljava/lang/String; 3 26 1 i I 6 23 2 j I 10 19 3 k I 14 15 4 s Ljava/lang/String;}SourceFile: "PCRegisterTest.java"

7.1使用PC寄存器存储字节码指令地址有什么用呢?或者问为什么使用 PC 寄存器来记录当前线程的执行地址呢?

7.2 PC寄存器为什么被设定为私有的?
注意并行和并发的区别,笔者的并发系列有讲


9.1举例
需要注意的是:标识符native可以与其它java标识符连用,但是abstract除外
public class IHaveNatives { public native void Native1(int x); public native static long Native2(); private native synchronized float Native3(Object o); native void Native4(int[] ary) throws Exception; }(1).Java使用起来非常方便,然而有些层次的任务用Java实现起来不容易,或者我们对程序的效率很在意时,问题就来了。
(2).与Java环境外交互
有时Java应用需要与Java外面的硬件环境交互,这是本地方法存在的主要原因。你可以想想Java需要与一些底层系统,如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解Java应用之外的繁琐的细节。
(3).与操作系统的交互
目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机或者Java系统管理生产设备,在企业级应用中已经比较少见。因为现在的异构领域间的通信很发达,比如可以使用Socket通信,也可以使用Web Service等等,不多做介绍。

注意事项