Java 执行过程详解 - JVM 生命周期

转载地址:http://jackycheng2007.iteye.com/blog/1473859


Java 执行过程详解 - JVM 生命周期


Java的执行过程也就是JVM从启动到退出的过程。JVM的运行是一个进程单元,可以用jps工具列举出正在运行的JVM 进程。在一个JVM进程中可以运行多个线程。 
1. JVM 启动 
当用java工具运行一个编译好的class文件的时候,比如下面的命令,我们就通过调用Test的main函数启动了一个JVM进程。并且传给main函数一个字符串数组{"reboot", "Bob", "Dot", "Enzo"} 

Java代码   收藏代码
  1. java Test reboot Bob Dot Enzo  

2. 加载类Test  
如果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完成之后,就可以连接这些类型,让他们进入可执行状态。 
3. 连接 Test: 验证 Verify, 准备 Prepare, 解析 (Optionally) Resolve  
在执行main之前要先初始化这个类,在初始化之前还要先连接,连接就是要验证,准备和解析。 
验证就是检查语法和符号表,如果失败会报错。 
准备就是要准备内存,主要为静态属性以及jvm内部需要的数据结构。这时只会将静态属性设置为默认值,但是静态代码块的执行不在这里,而是在初始化阶段。 

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


4.初始化 initialization  
在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. (不懂,求解) 
Java代码   收藏代码
  1. class Super {  
  2. static { System.out.print("Super "); }  
  3. }  
  4. class One {  
  5. static { System.out.print("One "); }  
  6. }  
  7. class Two extends Super {  
  8. static { System.out.print("Two "); }  
  9. }  
  10. class Test {  
  11. public static void main(String[] args) {  
  12. One o = null;  
  13. Two t = new Two();  
  14. System.out.println((Object)o == (Object)t);  
  15. }  
  16. }  


输出: 
Java代码   收藏代码
  1. Super Two false  

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

Java代码   收藏代码
  1. class Super {  
  2. static int taxi = 1729;  
  3. }  
  4. class Sub extends Super {  
  5. static { System.out.print("Sub "); }  
  6. }  
  7. class Test {  
  8. public static void main(String[] args) {  
  9. System.out.println(Sub.taxi);  
  10. }  
  11. }  

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

因为Java程序是多线程的,所以初始化过程需要同步synchronize,这是由jvm负责的。 
Class对象有可能处在下面的状态之下: 
1. 验证和准备好了,但还没有初始化 
2. 正在被某个线程初始化中 
3. 初始化好了,可以运行了 
4. 错误状态,初始化失败 


5. 调用 Test.main  
初始化好之后,就开始调用Test.main。这个main方法必须得是public, static, and void. 
Java代码   收藏代码
  1. public static void main(String[] args)  
  2. public static void main(String... args)  


6. 卸载类对象  
这是一个优化过程,是为了释放内存的,但是JVM说明书并不严格定义这一行为,这取决于具体实现的优化策略。
7. 程序退出  
当下面的条件之一发生的时候: 
1. 所有的非daemon线程都终止了 
2. 某个线程调用了类Runtime或者System的exit方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值