最近学习java,写上读书笔记 哈哈
java虚拟机启动后会引发类的一连串‘连锁反应’。java虚拟通过调用特定类中的main(该方法必须是public static void)方法开始执行。这将会引起此类以及他所引用的类被加载,链接,初始化。
加载过程把经过Java编译器编译后符合类文件格式的二进制java字节码文件加载到JVM中的过程。
类的加载过程是通过类加载器和它的子类实现的(比如需要对java字节码加密,那么加载到jvm中前就得解密,如何解密就得自己实现类加载器了)。不同的子类加载器有不同实现的加载机制。通常情况下,类加载器会缓存类或者是接口的二进制数据,以便有目的的预取使用,或者是加载一组相关的的类。这些动作对运行的应用程序是不透明的,如新编译的class不会被发现由于缓存机制(这也是为什么在做有些开发时要频繁启动应用服务器)。
链接
链接是把二进制格式的类或接口和java虚拟机运行时状态结合的过程,以便类能够被执行。类和接口通常是先加载到JVM中再链接。链接有三个活动,校验,准备,解析符号引用。
校验保证了类的结构是正确的,比如检查每条指令的操作码是有效的。校验时如果有错误发生,则LinkageError 的子类实例VerifyError将会被抛出。
准备过程包括创建接口或类的静态字段,用标准的默认值(比如int类型初始化为0)初始化这些字段。这个过程不需要执行任何java虚拟机代码。显示的初始化静态字段是在初始化时完成,并不是在准备过程,比如 static int i = 9;
java虚拟机的实现还在准备过程中会对一些而外的数据结构做些预处理工作,以便在后续对类和接口的操作更高效。例如方法表或者是别的一些数据结构可以使运行类实例在调用时不用搜索超类就可以调用任何方法。
在符号引用可以使用前必须对其解析,例如检查符号引用是否有效,或者是做些优化的工作。比如某个符号引用使用频率较高,则对其替换为一个直接引用以便虚拟机能高效的处理它。
初始化
类的初始化包括执行静态初始器和类中的静态字段初始器(即类变量的初始化和静态块的执行)。接口初始化即初始化接口中声明的字段。
类被初始化之前,其直接超类(父类)必须先于子类被初始化,该类实现的接口可以不被初始化。与此类似,某个接口初始化时其父接口可以不被初始化。
有一点很容易混淆也是不容易引起注意的是类的生命周期不等于对象的生命周期,一个类加载到虚拟机里直到该类的类加载器不可达(消亡)该类才会被卸载,bootstrap类加载器是总是可达的,也就是说系统的类永远不会被卸载(jvm还活着的情况)。
我认为Class对象是类信息的一个‘容器’,该类包含了运行时对象的属性,标识符,方法名,方法参数列表等信息。是供使用者了解该类的一个有效工具。
从上面来看,java中内存泄露主要是存在于对象创建后没有在适当的时候被GC回收掉而引起的,因为类的生命周期中,类只是为对象创建提供了一个模板,其本身不占用太多内存(JVM堆内存),但是在类的定义中如果有不正确的引用导致分配的对象没有释放掉,那么就造成了内存泄露。