虚拟机栈:
程序计数器(Program Counter):
本地方法栈:主要用于执行本地方法
堆(Heap):JVM管理的最大的一块内存空间
方法区:存储元数据。在HotSpot虚拟机中也叫永久代,从jdk1.8开始,已经彻底废弃了永久代,使用元空间代替
运行时常量池:方法区的一部分内容
直接内存
虚拟机栈:
主要由栈帧(每个方法会生成一个栈帧)构成,栈帧由局部变量表,操作数栈,动态链接,方法出口等。
public class Math{
public int compute(){
int a = 1;
int b = 2;
int c = a + b;
return c;
}
public static void main(String [] args){
Math math = new Math();
math.compute();
Math math2 = new Math();
math2.compute();
}
}
上述代码在编译成字节码之后实际上是执行相应的指令,首先会获取常量1将其压入操作数栈中,然后在局部变量表中开辟一段空间给a,接着从操作数栈将1出栈,并将其赋值个局部变量表中的a。然后b的操作与a相同,接着将1从局部变量表中拿出压入操作数栈,将2从局部变量表中拿出压入操作数栈,然后将操作数栈的两个数弹出,执行加法指令并将结果压入操作数栈,在局部变量表中开辟c的内存空间,将操作数栈的结果弹出赋值给c,也就是放入局部变量表中
程序计数器是和虚拟机栈都是线程独有的,程序计数器是保存当前线程执行指令的地址,当执行一条指令之后,程序计数器会自动更新,指向下一条指令的内存地址
方法出口:在执行完相应的方法之后,要回到调用该方法的位置处,所以需要保存调用出的内存地址
java对象:
jvm在装载Math.class时,会将class中的常量、静态变量,类的元数据(方法、接口、类名等)解析出来存放在方法区,例如方法解析之后会如下形式,存放了执行的指令,当new Math对象存放在堆中的时候,Math对象的对象头信息中保存了执行类元数据的地址,在执行相应的方法的时候实际上是一个链接符号,根据链接符号来到元数据中找到相应的方法,这个过程实际上是动态链接
public int compute();
Code:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: iload_3
9: ireturn
public static void main(java.lang.String[]);
Code:
0: new #1 // class bytecode/Math
3: dup
4: invokespecial #22 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #23 // Method compute:()I
12: pop
13: new #1 // class bytecode/Math
16: dup
17: invokespecial #22 // Method "<init>":()V
20: astore_2
21: aload_2
22: invokevirtual #23 // Method compute:()I
25: pop
26: return
虚拟机栈中的局部变量会引用堆中对象的引用,也就是内存地址,而堆中的对象会在对象头中引用该类的元数据,也就是会保存了一个在方法区的类元数据地址。
可达性分析算法:
这个算法的基本思想及时通过一系列的称为GC Roots的对象作为起点,从这些节点开始向下搜索,节点所走过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连的话,则证明此对象是不可用的。
GC Roots根节点:类加载器、Thread、虚拟机栈的局部变量表、static成员、常量引用、本地方法栈的局部变量等
堆:
堆内存分为新生代和老年代,新生代又细分为Edenq区和Survivor区(Survivor区又分为From区和To),默认情况下Eden区占新生代的8/10,From和To区各占1/10。一般情况下,新创建的对象是存放在堆内存中的Eden区,当Eden区满了的时候会触发jvm进行minor gc,清理Eden区的不可达对象,如果发现还存活的对象,则会将其移到From区,终究From区也会满,当From区满的时候也会触发minor gc,如果对象还存活,则会将存活对象移到To区,这时对象头中的分代年龄属性就会自动+1,记录其存活的状态,如果To区也满了,那么也会触发minor gc,还存活的对象则会被移到From区,同时分代年龄+1,分代年龄超过15的时候,存活对象就会移到老年代中,如果老年代内存已满,那么就会触发full gc