Java虚拟机的作用?
了解这个问题前,先搞清两个问题:
1.Java为何称为“高级”语言?
2.Java为何能一次编译多次(多系统)运行?
Ok!慢慢道来,众多周知硬件只能识别由二进制组存的机器语言,而机器语言则难以让人阅读;即便C语言
等编译后可直接转化为二进制的语言也是让人费解,于是更接近人类思维逻辑的“高级”语言便孕育而生;如java和现时火热的Python,但由于其高度抽象,也并不适合直接在硬件上运行。因此作为高级语言和机器语言间的枢纽虚拟机便诞生了,与此同时由于虚拟机的出现,只要装有支持Java的虚拟机的操作系统便可运行编译后的Java文件.class。虚拟机同时还承担着内存对象生命周期的管理、数组越界、动态类型、安全权限等,省去了非业务逻辑的开发。
JVM虚拟机运行时数据?
由.java文件经编译后的.class文件,此处省略1万字解释啥是编译器。
图1-1Java虚拟机运行时数据区
Java堆(Heap)
是Java虚拟机管理所占内存中最大的一块(其次大的是java方法栈),存在于线程共享的内存区,在虚拟机启动时创建。此区域唯一目的就是存放对象实例,几乎所有对象实例都在这分配内存,为何不是100%?JIT编译器,栈上分配、变量替换了解一下。
同时Java堆也是垃圾收集器管理的主要区域,同时也被称为“GC堆”(Garbage Collected Heap)。由于内存回收的进步,Java堆中还分为:新生代、老年代,TLAB等,但存储的仍是对象实例。在此不做过多描述,后续会专题讲解GC回收及内存分配空间不连续等问题。
方法区(Method Area)
也存在于线程共享的内存区,存储已被加载的类信息、常量、静态变量、即时编译器编译后的代码等;然而方法区的规范非常的宽松,不需要连续的内存和可选择固定大小或者扩展,甚至可以不选择垃圾回收,因此方法区的回收效果难以尽如人意;所以要求开发者在有关方法区编码时有所顾虑,其中著名的异常“OutOfMemoryError”就常出于此处。
程序计数器(Program Counter Register)
是寄存器的一种,然而它的作用仅仅是为了让CPU可以按顺序执行代码的临时寄存器;它记录着当前线程执行字节码的行号,而字节码解释器(CPU仍然无法识别字节码,需要字节码解释器)就是通过改变计数器的值来选取下一条执行字节码,分支、循环、跳转、异常处理、线程恢复等执行都需要计数器来完成。每个线程占有独立空间,拥有独立的计数器,各自互不影响;
值得一提的是,如果线程执行一个java方法则记录着正在执行的虚拟机字节码指令地址;如果线程执行的是Native方法则计数器为空(Undefined)。
Java虚拟机栈
它描述着的是Java方法执行的内存模型:每个方法都会创建一个帧栈,用于存放局部变量、操作数栈、动态链接、方法出口等信息;每一个方法的调用到执行完成,就对应着一个帧栈在虚拟机栈中入栈到出栈的过程,下图展示出入栈的信息:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #1 // class Exception/Foo
3: dup
4: invokespecial #37 // Method "<init>":()V
7: invokevirtual #38 // Method test:()V
10: return
LineNumberTable:
line 21: 0
line 22: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 args [Ljava/lang/String;
}
SourceFile: "Foo.java"
stack :最大操作数栈,JVM运行时会根据这个值来分配栈帧(Frame)中的操作栈深度,此处为2;
locals:局部变量所需的存储空间,单位为Slot, Slot是虚拟机为局部变量分配内存时所使用的最小单位,为4个字节大小;
args_size:方法参数的个数,这里是1,因为每个实例方法都会有一个隐藏参数this;(此处简单介绍,有兴趣自学JAVA字节码)
本地方法栈(Native Method Stack)
与Java虚拟机栈一样,只不过为Native方法服务,虚拟机规范中并无强制规定,具体的过程视对应的虚拟机而定。
了解上述模块,可知.class中的字节码进入方法区,虚拟机会执行其中的代码,在堆中分配实例对象空间,并在栈中执行;在运行过程中,每当调用进入一个 Java 方法,分配帧栈并经过入栈出栈等过程。
当然,Java 字节码无法直接执行。因此,Java 虚拟机需要将字节码翻译;如下图描述:
图1-2 截图来源为极客时间郑雨迪老师讲义(自认为无法更好表达该知识点,故截图摘抄,仅自我学习用)
总结
至此Java代码的运行过程大致描述清楚,更详细的请自行学习,也会不定期更新补全相关知识点。
1.虚拟机的作用?—向硬件解释字节码,同时管理内存对象生命周期、数组越界、动态类型、安全权限等。
2.虚拟机运行时相关数据的存放?—方法区存放类信息、常量、静态变量等;堆存放对象实例…
3.Java字节码的运行过程?—初始化各种内存空间后,便执行字节码,同时向硬件解释其意义。