论坛首页 编程语言技术论坛

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

浏览 9323 次
该帖已经被评为隐藏帖
作者 正文
   发表时间:2012-04-04   最后修改:2012-04-09
不好意思,本人是在写博客的时候选择发布到论坛的,在下不知道写在博客里的文章,后期的更新不会自动同步到论坛。只是在第一次发布的时候发送到论坛。本人绝对不是标题党。还请各位谅解。只希望大家可以自由交流,共同进步。下面我把内容补充完整了。欢迎交流。

Java的执行过程也就是JVM从启动到退出的过程。JVM的运行是一个进程单元,可以用jps工具列举出正在运行的JVM 进程。在一个JVM进程中可以运行多个线程。
1. JVM 启动
当用java工具运行一个编译好的class文件的时候,比如下面的命令,我们就通过调用Test的main函数启动了一个JVM进程。并且传给main函数一个字符串数组{"reboot", "Bob", "Dot", "Enzo"}
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. (不懂,求解)
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. 错误状态,初始化失败


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


6. 卸载类对象
这是一个优化过程,是为了释放内存的,但是JVM说明书并不严格定义这一行为,这取决于具体实现的优化策略。
7. 程序退出
当下面的条件之一发生的时候:
1. 所有的非daemon线程都终止了
2. 某个线程调用了类Runtime或者System的exit方法
   发表时间:2012-04-09  
太监了?继续写呀。。
0 请登录后投票
   发表时间:2012-04-09  
绝对的标题党
0 请登录后投票
   发表时间:2012-04-09  
哇,好详细。真不愧,“详解” 。楼主大才,巨才
0 请登录后投票
   发表时间:2012-04-09  
你又发到博客频道了,这里没有同步过来。以后还是直接整到论坛吧。
0 请登录后投票
   发表时间:2012-04-10  
标题哥威武
0 请登录后投票
   发表时间:2012-04-12  
第五点没人解答啊
0 请登录后投票
   发表时间:2012-04-12  

继续写下去,免得别人看你笑话,前面写得不错,适合入门。 加油!!!
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics