当前位置: 首页 > >

Java 执行过程详解

发布时间:

Java的执行过程也就是JVM从启动到退出的过程。JVM的运行是一个进程单元,可以用jps工具列举出正在运行的JVM 进程。在一个JVM进程中可以运行多个线程。

[size=medium]1. JVM 启动[/size]

当用java工具运行一个编译好的class文件的时候,比如下面的命令,我们就通过调用Test的main函数启动了一个JVM进程。并且传给main函数一个字符串数组{"reboot", "Bob", "Dot", "Enzo"}


java Test reboot Bob Dot Enzo

[size=medium]2. 加载类Test[/size]

如果JVM发现Test类还没有被加载,就会调用class loader去加载这个类的class 文件。

加载类,就是说ClassLoader 利用它的defineClass 方法来从class文件构建Class对象。

ClassLoader 应该有如下的特征:

1. 对于同一个类名,ClassLoader 多次load得到的类对象应该是一样的。

2. 如果ClassLoader L1 委托ClassLoader L2去load类C,对于任意类型T,如果T是C的直接父类或接口,或者是C的属性的类型,或者是C的方法的参数的类型或者返回值的类型,那么L1和L2 load出来的T的类的对象应该是一样的。



load完成之后,就可以连接这些类型,让他们进入可执行状态。

[size=medium]3. 连接 Test: 验证 Verify, 准备 Prepare, 解析 (Optionally) Resolve[/size]

在执行main之前要先初始化这个类,在初始化之前还要先连接,连接就是要验证,准备和解析。

验证就是检查语法和符号表,如果失败会报错。

准备就是要准备内存,主要为静态属性以及jvm内部需要的数据结构。这时只会将静态属性设置为默认值,但是静态代码块的执行不在这里,而是在初始化阶段。



解析就是检查这个Test对其他的对象或接口的引用,看看是不是那些引用的类和接口也被load进来了。没有的话就要load。解析过程是可选的,是因为你可以选择在load Test的时候load所有Test应用的类和接口,也可以在运行时真正用到的时候再load,也就是lazy load。





[size=medium]4.初始化 initialization[/size]

在main执行之前,必须先对类进行初始化。初始化类的变量,还有静态代码块。初始化的时候还要先初始化它的父类。每个类都有一个隐含的父类Object。

初始化过程发生在:

1. T是一个类,当T的一个实例创建的时候,也就是T t = new T();

2. T的一个静态方法被调用的时候,也就是 T.staticField();

3. T的静态属性被赋值的时候,T.staticField = o;

4. T的一个静态属性被使用的时候,也就是 Object o = T.staticField; 但是它不是常量。

5. T is a top level class , and an assert statement lexically nested

within T is executed. (不懂,求解)


class Super {
static { System.out.print("Super "); }
}
class One {
static { System.out.print("One "); }
}
class Two extends Super {
static { System.out.print("Two "); }
}
class Test {
public static void main(String[] args) {
One o = null;
Two t = new Two();
System.out.println((Object)o == (Object)t);
}
}




输出:


Super Two false

One没有被初始化,因为没有被调用过,Super在Two之前初始化。





class Super {
static int taxi = 1729;
}
class Sub extends Super {
static { System.out.print("Sub "); }
}
class Test {
public static void main(String[] args) {
System.out.println(Sub.taxi);
}
}


输出: 1729

Sub没有被初始化,因为taxi实际上上Super的属性。Sub没有静态属性被使用,所以不被初始化。所以不要在子类里面初始化父类的静态变量。



因为Java程序是多线程的,所以初始化过程需要同步synchronize,这是由jvm负责的。

Class对象有可能处在下面的状态之下:

1. 验证和准备好了,但还没有初始化

2. 正在被某个线程初始化中

3. 初始化好了,可以运行了

4. 错误状态,初始化失败





[size=medium]5. 调用 Test.main[/size]

初始化好之后,就开始调用Test.main。这个main方法必须得是public, static, and void.


public static void main(String[] args)
public static void main(String... args)




[size=medium]6. 卸载类对象[/size]

这是一个优化过程,是为了释放内存的,但是JVM说明书并不严格定义这一行为,这取决于具体实现的优化策略。

[size=medium]7. 程序退出[/size]

当下面的条件之一发生的时候:

1. 所有的非daemon线程都终止了

2. 某个线程调用了类Runtime或者System的exit方法




相关资源:Java虚拟机和Java程序的生命周期



友情链接: hackchn文档网 营销文档网 爱linux网 爱行业网 时尚网