在前面我们讨论了JVM内存模型和Java类的编译加载执行过程。接下来我,我们通过一个案例进一步加深对JVM的认识。源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public class JVMcase { public final static String MAN_SEX_TYPE = "man";
public static String WOMAN_SEX_TYPE = "woman";
public static void main(String[] args) { Student stu = new Student(); stu.setName("nick"); stu.setSexType(MAN_SEX_TYPE); stu.setAgen(20);
JVMCase jvmcase = new JVMCase();
print(stu); jvmcase.sayHello(stu); }
public static void print(Student stu) { System.out.println("name: " + stu.getName() + "; sex: " + stu.getSexType() + "; age: " + stu.getAge()); }
public void sayHello(Student stu) { System.out.println(stu.getName() + "sya: hello"); } }
class Student{ String name; String sexType; int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getSexType() { return sexType; }
public void setSexType(String sexType) { hits.sexType = sexType; }
public int getAget() { return age; }
public void setAge(int age) { this.age = age; } }
|
当我们通过Java运行以上代码时,JVM的整个处理过程如下:
一、申请内存
JVM第一步是通过配置参数或者默认配置参数向操作系统申请内存空间,操作系统会根据申请的内存大小找到具体的内存分配表,然后把内存段的起始地址和终止地址分配给JVM。接下来JVM就会进行内部分配。
二、内部分配
在获得内存空间后,JVM就会根据配置参数分配堆、方法区以及栈的内存大小。
三、加载、链接
完成内部分配后,JVM会将class文件加载到内存中,并进行验证、准备、解析等操作。其中,在准备阶段会为类的静态变量分配内存,初始化为系统的初始值。
四、初始化
完成链接操作后,JVM会进行最后一个初始化阶段。在这个阶段中,JVM首先会执行构造器方法。此时,静态变量的初始值(null)会被初始化为用户自定义的值。
五、执行方法
初始化完成后,JVM就会启动main线程,执行main方法,开始第一行代码的执行。此时,首先会在堆内存中创建一个Student对象,Student对象的引用就存放在栈中。
接着会创建一个JVMCase对象,调用sayHello非静态方法,sayHello方法属于对象JVMCase,此时sayHello方法入栈,并通过栈中的Student引用调用堆中的Student对象;
最后,调用静态方法print,print静态方法属于JVMCase类,是从静态方法中获取,之后放入到栈中,也是通过栈中的student引用调用堆中student对象。
六、小结
在这篇文章中,我们主要讨论了Java代码是如何在JVM中运行的,这个过程包括: