一、Java 开发和运行环境中的核心组件
1.JDK
定义:Java 开发工具包,包含开发 Java 应用程序所需的所有工具和库。
组成:
-
JRE: 用于运行 Java 程序。
-
编译器 (javac): 将 Java 代码编译为字节码。
-
调试工具: 如 jdb。
-
其他工具: 如 jar、javadoc 等。
作用:主要用于开发 Java 应用程序。
2.JRE
定义: Java 运行时环境,提供运行 Java 程序所需的环境。
组成:
-
JVM: 执行字节码。
-
核心类库: 提供标准 API。
-
其他支持文件: 如资源文件。
作用:用于运行已编译的 Java 程序,不包含开发工具。
3.JVM
定义: Java 虚拟机,负责执行 Java 字节码。
组成:
-
加载字节码: 通过类加载器加载。
-
执行字节码: 通过解释器或 JIT 编译器执行。
-
内存管理: 包括垃圾回收。
作用:是 Java 跨平台的核心,确保程序在不同操作系统上运行。
关系总结
-
JDK 包含 JRE 和开发工具。
-
JRE 包含 JVM 和运行 Java 程序所需的库。
-
JVM 是运行 Java 字节码的虚拟机。
二、JVM中的内存区域划分
JVM其实也是一个进程(任务管理器中拿到的java进程)
进程运行过程中,要从操作系统这里申请一些资源(内存就是典型资源)。这些内存空间,就支持了后续Java程序的运行。比如:在Java中定义变量(就会申请内存),内存其实就是jvm从系统申请到的内存。
jvm从系统申请了一大块内存,这一大块内存给Java程序使用的时候,又会根据实际使用用途来划分不同的空间(“区域划分”)
类似的,jvm申请到的空间,也会划分出几个区域,每个区域有不同的作用。
1.堆:
代码中new出来的对象都在堆里,对象持有的非静态成员变量也在堆里。
2.栈:
包含了方法调用关系和局部变量。
本地方法栈:通过c++写的代码,jvm内部调用关系和局部变量(一般不会关注本地方法栈)
虚拟方法栈:记录了Java代码的调用过程,Java代码的局部变量(默认指的是虚拟方法栈)
3.程序计数器:
专门用来存储下一条要执行的Java指令的地址,这个区域比较小的空间
4.元数据区:
(在Java以前版本中也叫“方法区”,从1.8开始改为元数据区)
“元数据”是计算机中的一个常见术语(meta data)往往指的是一些辅助性质的,描述性质的属性。
硬盘上不仅要存文件的数据本体,还要存储一些辅助信息,比如(文件的大小,位置,拥有者,权限信息......)统称为“元数据”。
一个程序中有哪些类,每个类中有哪些方法,每个方法里包含了哪些指令,都会记录在元数据区。
程序员写的Java代码,if、while、for各种逻辑运算,这些操作最终都会被转换成Java字节码(javac就会完成上述代码 => 字节码)此时,这些字节码在程序运行的时候会被jvm加载到内存中,放到元数据区(方法区)中。
此时,当前程序要如何执行,要做哪些事情,就会按照上述元数据区里记录的字节码依次执行了。
注:
堆,元数据区只有一份。
栈,程序计数器可能有N份 => 每个线程都有自己的程序计数器和栈(每个线程有自己的执行流)
典型笔试题
上述代码中t,n,m分别处在jvm内存中的哪个区域?
1. t (对象引用)
-
存储区域: 栈(Stack)
-
说明:
t
是一个局部变量,存储的是对Test
对象的引用。局部变量和方法调用栈帧存储在栈内存中。
2. n (实例变量)
-
存储区域: 堆(Heap)
-
说明:
n
是Test
类的实例变量,存储在堆内存中。每个Test
对象实例都有自己的一份n
变量。
3. m (静态变量)
-
存储区域: 方法区(Method Area)
-
说明:
m
是Test
类的静态变量,存储在方法区中。静态变量属于类级别,所有实例共享同一个m
变量。
static修饰的变量,称为“类属性”,修饰的方法,称为“类方法”。
非static修饰的变量,称为“实例属”,修饰的方法,称为“实例方法”。
上述带有static修饰的变量,是在类对象中的,也就是在元数据区的。
jvm把.class文件加载到内存之后,就会把这里的信息使用对象来表示,此时,这样的对象就是类对象,类对象中包含了一系列的信息:(包括:类的名称,类继承自哪个类,实现了哪些接口,有哪些属性,方法......)
.java文件中涉及到的信息,都会在.class中有所体现(注释是不会包含的)
区分一个变量在哪个内存区域中,最主要是看变量的形态(局部变量,成员变量,静态成员变量)