文章目录
概述
本文分析Windows平台下,一个简单Hello World程序从编译到运行所经历的大致过程,Test.java
代码如下:
|
|
执行步骤
- 命令行执行
javac Test.java
,编译成.class
文件。 - 命令行执行
java Test
,控制台打印结果Hello World!
。
执行步骤详细分析
一、把.java文件编译成.class
执行javac Test.java
命令时,javac编译器将按照《Java虚拟机规范》把Test.java
源文件编译成平台无关的Test.class
文件,该Class文件的结构可以被虚拟机识别。
二、加载.class文件到JVM
执行java Test
命令时,java.exe
会装载jvm.dll
这个动态链接库,启动虚拟机进程,把Test.class
文件加载到虚拟机内存中,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。具体的类加载过程如下:
- 加载:应用程序类加载器(Application ClassLoader)获取
Test.class
的二进制字节流,将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构,并在内存中生成一个代表这个类的java.lang.Class
对象,作为方法区这个类的各种数据的访问入口。 - 验证:虚拟机对该Class文件的字节流进行一系列验证(文件格式验证、元数据验证、字节码验证、符号引用验证),确保符合当前虚拟机的要求,不会危害到虚拟机。
- 准备:为类变量(被static修饰的变量)分配内存并设置初始值,这些变量所使用的内存都将在方法区中进行分配。
- 解析:虚拟机常量池内的符号引用替换为直接引用。
- 初始化:根据程序员自定义的内容去初始化类变量和其他资源。
三、JVM执行字节码
使用javap -v Test
命令,可以看到main()
方法字节码如下:
|
|
详细字节码指令执行步骤如下:
- 执行
getstatic
指令,把static
修饰的System.out
的引用存入当前栈帧的操作数栈。 - 执行
ldc
指令,把字符串Hello World!
的引用从运行时常量池中存入操作数栈。 - 执行
invokevirtual
指令,调用PrintStream.println()
方法,该指令会使用前两步操作存入操作数栈的值。
参考文档
《深入理解Java虚拟机》
《The Java Virtual Machine Specification》
近期评论