1)局部变量区:
-
局部变量区是一个数组结构,主要存放对应方法的参数和局部变量。
-
如果是实例方法,局部变量表第一个参数是一个 reference 引用类型,存放的是当前对象本身 this。
2)操作数栈:
-
操作数栈也是一个数组结构,但并不是通过索引来访问的,而是栈的压栈和出栈操作。
-
操作数栈是虚拟机的工作区,大多数指令都要从这里弹出数据、执行运算、然后把结果压回操作数栈。
3)动态链接:
-
每个栈帧内部都包含一个指向当前方法所在类型的运行时常量池的引用,以便对当前方法的代码实现动态链接。
-
在class文件里面,一个方法若要调用其他方法,或者访问成员变量,则需要通过符号引用来表示,动态链接的作用就是将这些以符号引用所表示的方法转换为对实际方法的直接引用。
4)方法返回:
- 方法执行后,有两种方式退出该方法:正常调用完成,执行返回指令。异常调用完成,遇到未捕获异常,不会有方法返回值给调用者。
本地方法栈
本地方法栈与虚拟机栈所发挥的作用是相似的,当线程调用Java方法时,会创建一个栈帧并压入虚拟机栈;而调用本地方法时,虚拟机会保持栈不变,不会压入新的栈帧,虚拟机只是简单的动态链接并直接调用指定的本地方法,使用的是某种本地方法栈。比如某个虚拟机实现的本地方法接口是使用C连接模型,那么它的本地方法栈就是C栈。
本地方法可以通过本地方法接口来访问虚拟机的运行时数据区,它可以做任何他想做的事情,本地方法不受虚拟机控制。
程序计数器
每一个运行的线程都会有它的程序计数器(PC寄存器),与线程的生命周期一样。执行某个方法时,PC寄存器的内容总是下一条将被执行的地址,这个地址可以是一个本地指针,也可以是在方法字节码中相对于该方法起始指令的偏移量。如果该线程正在执行一个本地方法,那么此时PC寄存器的值是 undefined。
程序计数器是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。多线程环境下,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
代码在JVM内存中的体现
当我们通过Object o=new Object()
创建一个对象时,在JVM中会分配一块内存用来存储该对象的信息,实现原理如下图所示。
在main方法中,创建了一个局部变量o
,当main方法运行时,首先会把main方法压入到栈帧中,接着执行该方法的Object o =new Object()
创建对象。
-
在局部变量表中创建一个局部变量
o
。 -
在堆内存中分配一块内存地址,用来存储
object
对象。 -
变量
o
指向堆内存中的内存地址。
我们再来看一个例子,声明一个Person对象,在该对象中存在一个常量name
、以及一个成员变量age
,当运行该类中的main
方法时,此时JVM内存中的运行情况如下。
在这个例子中,看到了常量池的出现,看来,还有必要了解一下常量池的知识
JVM中的常量池
在JVM中,常量池主要分为:Class文件常量池、运行时常量池,当然还有全局字符串常量池,以及基本类型包装类对象常量池。
常量池主要存放两大类常量:字面量和符号引用。
-
字面量:字面量主要是文本字符串、final 常量值、类名和方法名的常量等。
-
符号引用:符号引用对java动态连接起着非常重要的作用。主要的符号引用有:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。
Class文件常量池
class文件是一组以8位字节为单位的二进制数据流,在java代码的编译期间,我们编写的.java文件就被编译为.class文件格式的二进制数据存放在磁盘中,其中就包括class文件常量池。
为了更好的说明,我们通过下面这段代码为例进行讲解。
class ConstantExample{
private int value = 1;
public String s = “abc”;
public final static int f = 0x101;
public void setValue(int v){
final int temp = 3;
this.value = temp + v;
}
public int getValue(){
return value;
}
}
这段代码被编译后,通过javap -v
命令查看编译后的字节码。
从下面这个字节码信息中可以看到,执行这个命令之后我们得到了该class文件的版本号、常量池、已经编译后的字节码指令(处于篇幅原因这里省略),下面我们会对照这个class文件来讲解:
example/target/classes/HelloExample.class
Last modified 2021-10-25; size 734 bytes
MD5 checksum fd06c1426f4fdef12aa109ee7f010a45
Compiled from “HelloExample.java”
public class HelloExample
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#32 // java/lang/Object.“”😦)V
#2 = Fieldref #5.#33 // HelloExample.value:I
#3 = String #34 // abc
#4 = Fieldref #5.#35 // HelloExample.s:Ljava/lang/String;
#5 = Class #36 // HelloExample
#6 = Class #37 // java/lang/Object
#7 = Utf8 value
#8 = Utf8 I
#9 = Utf8 s
#10 = Utf8 Ljava/lang/String;
#11 = Utf8 f
#12 = Utf8 ConstantValue
#13 = Integer 257
#14 = Utf8
#15 = Utf8 ()V
#16 = Utf8 Code
#17 = Utf8 LineNumberTable
#18 = Utf8 LocalVariableTable
#19 = Utf8 this
#20 = Utf8 LHelloExample;
#21 = Utf8 getValue
#22 = Utf8 ()I
#23 = Utf8 setValue
#24 = Utf8 (I)V
#25 = Utf8 MethodParameters
#26 = Utf8 main
#27 = Utf8 ([Ljava/lang/String;)V
#28 = Utf8 args
#29 = Utf8 [Ljava/lang/String;
#30 = Utf8 SourceFile
#31 = Utf8 HelloExample.java
#32 = NameAndType #14:#15 // “”😦)V
#33 = NameAndType #7:#8 // value:I
#34 = Utf8 abc
#35 = NameAndType #9:#10 // s:Ljava/lang/String;
#36 = Utf8 HelloExample
#37 = Utf8 java/lang/Object
字面量
字面量接近于java语言层面的常量概念,主要包括:
- 文本字符串,也就是我们经常声明的:
public String s = "abc";
中的"abc"
#3 = String #34 // abc
- 用final修饰的成员变量,包括静态变量、实例变量和局部变量
#11 = Utf8 f
#12 = Utf8 ConstantValue
#13 = Integer 257
这里需要说明的一点,上面说的存在于常量池的字面量,指的是数据的值,也就是abc
和0x101(257)
,通过上面对常量池的观察可知这两个字面量是确实存在于常量池的。而对于基本类型数据(甚至是方法中的局部变量),也就是上面的private int value = 1
;常量池中只保留了他的的字段描述符I
和字段的名称value
,他们的字面量不会存在于常量池:
符号引用
符号引用主要涉及编译原理方面的概念,包括下面三类常量:
- 类和接口的全限定名,也就是
Ljava/lang/String;
这样,将类名中原来的".“替换为”/"得到的,主要用于在运行时解析得到类的直接引用.
#5 = Class #36 // HelloExample
#6 = Class #37 // java/lang/Object
- 字段的名称和描述符,字段也就是类或者接口中声明的变量,包括类级别变量(static)和实例级的变量
#2 = Fieldref #5.#33 // HelloExample.value:I
#7 = Utf8 value
#8 = Utf8 I
运行时常量
运行时常量池是方法区的一部分,所以也是全局共享的。我们知道,jvm在执行某个类的时候,必须经过加载、连接(验证,准备,解析)、初始化,在第一步的加载阶段,虚拟机需要完成下面3件事情:
- 通过一个类的**“全限定名”来获取此类的二进制字节流**
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
[外链图片转存中…(img-4J9EXGls-1715514603173)]
[外链图片转存中…(img-enhPp5KA-1715514603174)]
[外链图片转存中…(img-YsX6s3kv-1715514603174)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!