-
Java虚拟机内存
Java虚拟机在执行Java程序的时候会将它管理的内存分为若干个不同的数据区域。不同的区域用途也各不相同,具体内存模型图如下图所示:
Java内存模型.png
其中橙色部分为线程私有的数据区域,蓝色部分为线程共享的数据区域
程序计数器
程序计数器是一块较小的内存空间,主要记录当前线程执行的虚拟机字节码地址,如果执行的是Native方法,则程序计数器值为空。
虚拟机栈
虚拟机栈描述的是Java方法的内存模型:每个方法在执行的时候都会创建一个栈帧,用来存储局部标量表、操作数栈、动态链接、方法出口等信息
本地方法栈
本地方法栈与虚拟机栈作用相似,不同的是本地方法栈是用于描述Native方法的内存模型
堆
Java堆是Java虚拟机所管理内存中最大的一块,也是被所有线程共享的一块内存区域,该区域主要是存放对象实例。Java堆也是垃圾收集器的主要区域,从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆还可以细分为新生代和老年代,再细致一点的有Eden空间、From Survivor空间、To Survivor空间等
方法区
方法区也是被各个线程共享的内存区域,主要用于存储被虚拟机加载的类信息、常量静态变量、即时编译器编译后的代码等数据 - Java虚拟机是如何操作这些区域的
结合代码重点了解一下JVM运行时数据区,主要是虚拟机栈的分析
com.kons;
public class Test{
public static void main(String[] args){
int a=1;
int b=2;
int c=add(a,b);
}
public static int add(int a,int b){
return a+b;
}
}
首先Test类被编译成class文件,通过类加载子系统加载到内存中。然后,JVM会给执行的线程分配程序计数器、虚拟机栈、以及本地方法栈,如图所示:

虚拟机栈.png
当执行main方法的时候,会给main方法创建一个栈帧压入虚拟机栈中,同理,当执行到add方法时也是如此,如图所示:

入栈.png
栈帧内部主要由局部变量,操作数栈,动态链接以及方法出口等及部分组成,接下来结合class文件了解一下,这个栈帧具体是怎么工作的。
打开class文件所在文件夹,通过javap命令查看class文件
javap -c Test.class >test.txt
代码如图所示:
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static int add(int, int);
Code:
0: iload_0
1: iload_1
2: iadd
3: ireturn
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: invokestatic #2 // Method add:(II)I
9: istore_3
10: return
}
执行流程
iconst_1:将整数1推到操作数栈上
istore_1:栈顶元素出栈并存入局部变量表1号位
iconst_2:将整数2推到操作数栈上
istore_2:栈顶元素出栈并存入局部变量表2号位

stack.png
iload_1:将局部变量表1号位元素放入栈顶
iload_2:将局部变量表2号位元素放入栈顶

iload.png
invorkestatic:调用静态方法add,该指令将弹出栈顶数据作为方法的参数并放入add栈帧中的局部变量表中

add.png
iload_0,iload_1:将局部变量表的数据压入操作数栈

add_load.png
执行到iadd的时候,操作数栈将数据相加并压入栈,执行完后,通过方法出口返回到main方法,并将add栈帧弹出虚拟机栈,最后通过istore指令将返回的数据存入局部变量表中

return.png
参考资料
《深入Java虚拟机》
