你好,我是吴计可师,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。
聊到内存区域划分,很久多人都会说,“这个简单,八股文天天背”,但是当面试官问你,“int a=1; 这个里面有涉及到的数据,变量等放到哪个区?”
“额?。。”
好了,我们先来复习一下功课,我们简单的就不详细过了,直接我们的经典图:
清晰明了,我们再上个表对比:
划重点,图跟表中的每个文字都是重点,共享性,内存溢出的报错现象等,都会成为一个考点
背好了没有,我们继续了。
举例说明
public class Example {
// 静态变量(存储在方法区)
private static String staticVar = "Static Variable";
// 实例变量(存储在堆中)
private int instanceVar;
// 常量(存储在运行时常量池)
private static final String CONSTANT = "Constant String";
public Example(int value) {
this.instanceVar = value; // 实例变量赋值
}
// 方法(字节码存储在方法区)
public void display() {
// 局部变量(存储在栈中)
int localVar = 42;
// 字符串常量(存储在运行时常量池)
String message = "Hello, World";
System.out.println(message + ", localVar: " + localVar + ", instanceVar: " + instanceVar);
}
public static void main(String[] args) {
// 对象(存储在堆中)
Example example = new Example(100);
example.display();
}
}
数据存储分布分析
程序计数器
每个线程执行程序时使用的指令地址存储在程序计数器中。
示例中涉及程序计数器的内容为线程正在执行的指令地址(例如 example.display() 的调用指令)
虚拟机栈
局部变量 localVar 存储在虚拟机栈中。
方法调用时传递的引用变量(如 this)也存储在栈中。
每个线程对应一个虚拟机栈,每个方法调用对应一个栈帧。
在 display() 方法中:
本地方法栈
如果程序中使用了本地方法(如 JNI),本地方法栈会存储对应的调用状态。
此示例未涉及本地方法,本地方法栈为空。
堆
所有对象实例存储在堆中。
示例中的对象 example 存储在堆中。
对象中的实例变量(instanceVar)也存储在堆中,属于对象的一部分。
方法区
存储类的元信息、静态变量、常量等。
示例中的静态变量 staticVar 和静态常量 CONSTANT 存储在方法区。
类 Example 的字节码也存储在方法区。
运行时常量
存储编译期生成的字面量和符号引用。
示例中字符串常量 "Constant String" 和 "Hello, World" 存储在运行时常量池中。
直接内存
用于与操作系统进行 I/O 数据交互。
示例中未直接使用直接内存。
本地方法栈
本地方法栈是 JVM 中专门为本地方法(通常由 JNI 调用的非 Java 语言方法,如 C/C++)提供的运行时内存区域。以下是一个使用本地方法栈的示例:
public class NativeExample {
// 加载本地库
static {
System.loadLibrary("nativeLib");
}
// 声明一个本地方法(Native Method)
public native void nativeMethod();
public static void main(String[] args) {
NativeExample example = new NativeExample();
// 调用本地方法
example.nativeMethod();
}
}
对应的 C 代码实现
假设我们用 C 语言实现 nativeMethod,并将其编译为一个动态链接库 nativeLib(如 nativeLib.dll 或 libnativeLib.so):
// 本地方法实现
JNIEXPORT void JNICALL Java_NativeExample_nativeMethod(JNIEnv *env, jobject obj) {
printf("Hello from native code!\n");
}
本地方法栈解析
当 nativeMethod 被调用时,JVM 会使用本地方法栈存储 C 方法的调用状态和相关数据。
本例中,C 方法 Java_NativeExample_nativeMethod 的调用状态存储在本地方法栈中。
JVM 加载本地库:通过 System.loadLibrary ("nativeLib") 加载本地动态链接库。
调用 native 方法:执行 example.nativeMethod(),JVM 检测到这是一个 native 方法,切换到本地方法栈,并通过 JNI 调用底层的 C 方法。
执行 C 方法:C 方法 Java_NativeExample_nativeMethod 被调用,实际在本地方法栈中运行,并打印字符串 "Hello from native code!"。
返回 Java:本地方法执行完毕后,将控制权交回 JVM,程序继续执行后续的 Java 代码。
好了,今天就分享这么多,喜欢可以点赞,关注