我们以分析下面的类为过程来讨论上面的每个模块。
package JVM;
import java.lang.ref.SoftReference;
public class Test {
public static int initData=1;
public static User user=new User();
public static SoftReference<User> user1=new SoftReference<>(new User());//软引用
public int sum(){
int a=1;
int b=2;
int c=a+b;
return c;
}
public static void main(String[] args) {
User user=new User();
user.sum();
}
}
第一步:首先是编译器把Test.java文件转为字节码文件即是Test.class文件。
第二步:是通过上面的类加载系统把这个Test.class字节码文件加载到运行时时区内的方法区内。
方法区内放的是类的信息:主要包括以下信息
- 类的完整名称
- 类的直接父类的完整名称
- 类的直接实现接口的有序列表
- 类的修饰符
- 符号引用
- 常量
- 静态变量
- 类的方法的信息
第三步:执行。把各种类的信息放好之后,下面就通过上面的字节码执行引擎开始执行方法区里面的指令(也就是类的字节码符号),我们假设当找到main()时,看看main()方法的第一条指令,第一条指令是去常量池中查找User类的符号引用,查找到这个符号之后就检查方法区内是否有指针把这个符号引用替换为指针并执行了这个User对象,当JVM发现还没有加载过一个User类时,他就开始查找并加载User类,并把User类的信息放到方法区,并把Test类中的方法取内对User类的符号引用换为一个指针直接指向User类,以后就用这个指针快速找到User类。替换之后,JVM就要为这个User类的实例对象user分配堆内存了,这是JVM就会利用刚才的指针指向这个类看看应该为他的实例对象申请多大的堆内存。jvm总能够从存储在方法区中的类型信息知道某类型对象需要的空间。一旦jvm知道了一个Lava对象所要的空间,它就在堆上分配这个空间并把这个实例的变量speed初始化为缺省值0。假如lava的父对象也有实例变量,则也会初始化。然后是去执行第二条指令是去执行sum()方法,这时候JVM会为这个方法在虚拟机栈中分配一个叫栈帧的内存,其实就是里面放的就是sum()方法的所有内容,如下所示:
执行完上述方法之后再执行main(),因此指令就结束了。