JVM内存结构
JVM中包括虚拟机栈、本地方法栈、程序计数器、堆、方法区,JDK8之后,Java虚拟机运行时数据区没有了方法区,被本地内存中新增的元空间替代 字符串常量池位置: JDK1.6:方法区 JDK1.7:堆 JDK1.8:堆 下面为了画图方便,用JDK1.6的内存结构来画
我们先定义3个类,Test.java,Obj.java,Run.java
class Test {
int a;
String s;
Obj o;
public Test(int a, String s, Obj o) {
this.a = a;
this.s = s;
this.o = o;
}
}
class Obj {}
class Run {
public static void main(String[] args) {
Test t = new Test(2,"haha",new Obj());
}
}
当执行了Run类中的main方法时会发生什么?
-
首先在栈中添加一个main方法的栈帧,局部变量t位于局部变量表中
-
开始执行
Test t = new Test(2,"haha",new Obj());
这一句代码的右半部分
new Test(2,"haha",new Obj())
中的new Test
,因为是第一次使用Test.class类,所以需要将Test.class的字节码信息加载到方法区中 -
Test类中包含了Obj类,所以又加载了Obj.class
-
在堆中开辟一块内存空间,这块空间的大小可以看这篇文章,Java中对象在内存中的布局 这四步如下图:
- 开始准备需要传递的参数:2,"haha",new Obj(),调用
public Test(int a, String s, Obj o) {
this.a = a;
this.s = s;
this.o = o;
}
Test类的这个构造方法,所以需要在栈中增加一个栈帧 6. 将2加入到操作数栈
-
先在字符串常量池中创建haha的字符串,并将地址0x77d37777加入到操作数栈
-
传入的Obj.class类的实例,所以在堆中开辟一块内存空间0x88d388888并触发Obj.class的构造函数,栈中新增Obj构造方法栈帧,然后栈帧销毁,将0x88d388888地址加入操作数栈
这几步如下图:
-
将main栈帧中的操作数栈出栈,作为参数调用Test的构造方法,栈中新增Test构造方法栈帧,局部变量赋值
10.将Test栈帧出栈并将引用赋值给main中的t变量
画重点!!!!
第10这里将引用和变量t建立关联,这一步不一定是发生在最后,在发生指令重排序的时候,是有可能在第4步,在堆中开辟内存空间之后就建立了关联