jvm的生命周期

突发灵感想到jvm 的生命周期,就花了一点时间来整理了一下,特此分享,如果分享不对,欢迎各位指正,谢谢!废话不多说,走起!

jvm实例的诞生
        当一个程序启动,伴随的就是一个jvm实例的诞生,当这个程序关闭退出,这个jvm实例就随之消亡。如果在同一台机器上运行多个程序,将诞生相应数量的jvm实例,每个程序都有一个与之对应的jvm实例供其运行。任何一个拥有公开的(public)、静态的(static)、没有返回值(void)并且接受一个字符串数组参数(String[] args) 的main()函数的class都可以作为JVM实例运行的起点 。
jvm实例的运行
         main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程。java程序的初始线程 只就是运行main()的线程,这个线程是非守护线程,只要还有任何非守护线程还在运行,那么jvm就存活着。
jvm实例的消亡
        当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用
java.lang.Runtime类或者java.lang.System.exit()来退出。


类加载:指的是类的生命周期中加载、连接、初始化三个阶段。就是找到需要加载的类并把类的信息加载到jvm的方法区中,然后在堆区中实例化一个java.lang.Class对象,作为方法区中这个类的信息的入口。
加载:类的加载方式比较灵活,我们最常用的加载方式有两种,一种是根据类的全路径名找到相应的class文件,然后从class文件中读取文件内容;另一种是从jar文件中读取。
连接: 连接阶段比较复杂,一般会跟加载阶段和初始化阶段交叉进行,这个阶段的主要任务就是做一些加载后的验证工作以及一些初始化前的准备工作,可以细分为三个步骤:验证、准备和解析。
        验证:当一个类被加载之后,必须要验证一下这个类是否合法,比如这个类是不是符合字节码的格
式、变量与方法是不是有重复、数据类型是不是有效、继承与实现是否合乎标准等等。总之,这个阶段的目的就是保证加载的类是能够被jvm所运行。
        准备:准备阶段的工作就是为类的静态变量分配内存并设为jvm默认的初值,对于非静态的变量,则不会为它们分配内存。有一点需要注意,这时候,静态变量的初值为jvm默认的初值,而不是我们在程序中设定的初值。
jvm默认的初值是这样的:
        1. 基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0。
        2. 引用类型的默认值为null。
        3. 常量的默认值为我们程序中设定的值。
        解析:这一阶段的任务就是把常量池中的符号引用转换为直接引用。 例如我们要在内存中找一个类里面的一个叫做show的方法,显然是找不到。但是在解析阶段,jvm就会把show这个名字转换为指向方法区的的一块内存地址,通过内存地址就可以找到show这个方法具体分配在内存的哪一个区域了。这里show就是符号引用,而内存地址就是直接引用。在解析阶段,jvm会将所有的类或接口名、字段名、方法名转换为具体的内存地址。
        连接阶段完成之后会根据使用的情况(直接引用还是被动引用)来选择是否对类进行初始化。
初始化:如果一个类被直接引用,就会触发类的初始化。在java中,直接引用的情况有:
        1. 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法;
        2. 通过反射方式执行以上三种行为;
        3. 初始化子类的时候,会触发父类的初始化;
        4. 作为程序入口直接运行时(也就是直接调用main方法)。
       除了以上四种情况,其他使用类的方式叫做被动引用,而被动引用不会触发类的初始化。


初始化过程:按照顺序自上而下运行类中的变量赋值语句和静态语句,如果有父类,则首先按照顺序运行父类中的变量赋值语句和静态语句。 在类的初始化阶段,只会初始化与类相关的静态赋值语句和静态语句,也就是有static关键字修饰的信息,而没有static修饰的赋值语句和执行语句在实例化对象的时候才会运行。

你可能感兴趣的:(jvm,jvm,java)