Java类型的生命周期
以上就是我今天没有总结学习类加载器时候对类加载器仅有的知识,虽然有个大概印象,但是还是有点模糊。今天一口气总结一下,参考文献我就不列举了。本文不生产知识,只是知识的搬运工。
静态.class文件到内存实例
这个话题可以换一个说法就是类的生命周期是什么样的?这个可以分为两部分:
- .class类文件变为class对象:装载、连接和初始化
- class对象实例化最后gc:类实例化,垃圾收集
图 1 Java中类和对象的生命周期
类型装载、连接与初始化
Java虚拟机通过装载、连接和初始化一个java类型,使该类型可以被正在运行的Java程序所使用。
- 装载:把二进制形式的Java类型读入Java虚拟机中。
- 连接:把这种已经读入了虚拟机的二进制形式的类型合并到虚拟机的运行时状态中;连接阶段分为三个子步骤:
- 验证:确保Java类型数据格式正确并且适于Java虚拟机使用。
- 准备:为该类型分配它所需的内存,比如为类变量分配内存。
- 解析:负责把常量池中的符号引用转为直接引用,虚拟机的实现可以推迟解析这一步,它可以在当运行中的程序真正使用某个符号引用时再去解析它(把该符号引用转换为直接引用)。
- 初始化:为了让一个类或者接口被首次主动使用,最后一个步骤就是初始化,也就是为类变量赋予正确的值。
图2 类型声明周期的开始
就像图2中看到的那么样,装载、连接和初始化这三个阶段必须按顺序进行。唯一的例子就是连接阶段的第三步——解析,它可以在初始化之后再进行。
类或接口的主动使用
在类和接口被装在和连接的时机上,Java虚拟机规范给实现提供了一定的灵活性。但是它严格定义了初始化的时机。所有的Java虚拟机实现必须在每个类或接口首次主动使用时初始化。以下六种情形都符合主动使用的要求:
- 当创建某个类的新实例时(或通过在字节码中执行new指令;或者通过不明确的创建、反射、克隆或者反序列化)。
- 当调用某个类的静态方法时(即在字节码中执行invokestatic指令时)。
- 当使用某个类或接口的静态字段,或者对该字段赋值时(即在字节码中,执行getstatic或putstatic指令时),用final修饰的静态字段除外,它被初始化为一个编译时的常量表达式。
- 当用Java API中的某些反射方法时,比如Class中的方法或者java.lang.reflect包中的类的方法。
- 当初始化某个类的子类时(某个类初始化时,要求它的超类已经被初始化了)。
- 当虚拟机启动时某个被标明为启动类的类(即含有main()方法的那个类)。
除了上述六种情形外,所有其他使用Java类型的方式都是被动使用,它们都不会导致Java类型的初始化。后面会有例子说明主动使用和被动使用的区别。
上面提到过,任何一个类的初始化都要求它的超类在此之前已经初始化了。以此类推,该规则就意味着某个类的所有祖先类都必须在该类之前被初始化。然而,这对于接口来说,这条规则并不适用。只有在某个接口所声明的非常量字段被使用时,该接口才会被初始化,而不会因为实现这个接口的子接口或者类要初始化而被初始化。因而,任何一个类的初始化都要求它的所有祖先类(而不是祖先接口)预先被初始化。而一个接口的初始化,并不要求它的祖先接口预先被初始化。
"在首次主动使用时初始化"这个规则直接影响着装载、连接和初始化类的机制。在首次主动使用时,其类型必须被初始化。然而,在类型能被初始化之前,它必须已经被连接了,而在它能被连接之前,它必须应被装载了。Java虚拟机的实现可以根据需要在更早的时候装载以及连接类型,没必要一直等到该类型的首次主动使用采取装载和连接它。无论如何,如果一个类型在它的首次主动使用之前还没有被装载和连接的话,那它必须在此时被装载和连接,这样它才能被初始化。
装载
装载阶段由三个基本动作组成,要装载一个类型,Java虚拟机必须:
- 通过该类型的完全限定名,产生一个代表该类型的二进制数据流。
- 解析这个二进制数据流为方法区内的内部数据结构。
- 创建一个表示该类型java.lang.Class类的实例。
这个二进制数据流可能遵守Java class文件格式,但是也可能遵守其他的格式。就像前一章提到的那样,所有的Java虚拟机实现必须能识别Java class文件格式,但是个别的实现可以识别其他的二进制格式。
Java虚拟机规范并没有说Java类型的二进制数据流应该怎样产生,额,产生方式就不赘述了,只有InputStream就可以啊。
有了类型的二进制数据之后,Java虚拟机必须对这些数据进行足够的处理,然后它才能创建类java.lang.Class的实例对象。虚拟机必须把这些二进制数据解析为与实现相关的内部数据结构。装载步骤的最终产品就是这个Class类的实例对象,它成为Java程序与内部数据结构之间的接口。要访问该类型的信息(它们是存储在内部数据结构中的),程序就要调用该类型对应的Class实例对象的方法。这样一个过程就是把一个类型的二进制数据解析为方法区中的内部数据结构、并在堆上建立一个Class对象的过程,这被称为"创建"类型。
Java类型要么由启动类装载器装载,要么通过用户自定义的类装载器装载。启动类装载器是虚拟机实现的一部分,它以与实现无关的方式转载类型(包括Java API的类和接口),用户自定义的类装载器是类java.lang.ClassLoader的子类实例,它以定制的方式装入类。
类装载器(启动型或者或用户自定义的)并不需要一直等到某个类型"首次主动使用"时再去装入它。Java虚拟机规范允许类装载器缓存Java类型的二进制表现形式,在预料某个类型将要被使用时装载它,或者把这些类型装载到一些相关的分组里面。如果一个类装载器在预先装载时遇到问题,无论如何,它应该在该类型被首次主动使用时报告该问题(通过抛出一个LinkageError异常的子类)。换句话说,如果一个类装载器在预先装载时遇到缺失或者错误的class文件,它必须等到程序首次主动使用该类时才报告错误。如果这个类一直没有被程序主动使用,那么该类装载器将不会报告错误。
验证
当类型被装载后,就准备进行连接了。连接过程的第一步是验证——确认符合Java语言的语义,并且它不会危及虚拟机的完整性。
准备
随着Java虚拟机装载了一个类,并执行了一些它选择进行的验证之后,类就可以进入准备阶段了。在准备阶段,Java虚拟机为类变量分配内存,设置默认初始值。但在到达初始化阶段之前,类变量都没有被初始化为真正的初始值。(在准备阶段是不会执行Java代码的。)
解析
类型经过了连接的前两个阶段——验证和准备——之后,它就可以进入第三个(也就是最后一个)连接阶段了——解析。解析过程就是在类型的常量池中寻找类、接口、字段和方法的符号引用,把这些符号引用替换成直接引用的过程。在前面提到过,在符号引用被程序首次使用之前,连接的这个步骤都是可选的。
初始化
为了准备让一个类或者接口被首次主动使用,最后一个步骤就是初始化,也就是为类变量赋予正确的初始值。这里的"正确"初始值指的是程序员希望这个类变量所具备的起始值。
1. <clinit>()方法
2. 主动使用和被动使用
对象的生命周期
一旦一个类装载、连接和初始化,它就随时可以使用了。程序可以访问它的静态字段,调用它的静态方法,或者创建它的实例。这里会讨论类的实例化和初始化,即对象生命起始阶段的活动,还要讨论垃圾收集和终结,即对象生命活动的尽头。
类实例化
垃圾收集和对象的终结
Java虚拟机实现必须具有某种自动堆存储管理策略——大部分是采用垃圾收集器。
卸载类型
装载、连接或初始化失败了会怎么样?
Reference
- 类和对象的生命周期:B.· 文纳斯 (美), 曹晓钢, 蒋靖. 深入 Java 虚拟机: 原书[M]. 机械工业出版社, 2003.
- 图1:JVM系列[1]-Java类的生命周期
Java类型的生命周期的更多相关文章
- [转]JAVA虚拟机的生命周期
JAVA虚拟机体系结构 JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的天职是:负责运行一个java程序.当启动一个Java程序时,一个虚拟机实例也就诞生了.当该程序关闭退出,这个虚拟机实例 ...
- java 静态变量生命周期(类生命周期)
Static: 加载:java虚拟机在加载类的过程中为静态变量分配内存. 类变量:static变量在内存中只有一个,存放在方法区,属于类变量,被所有实例所共享 销毁:类被卸载时,静态变量被销毁,并释放 ...
- Java类的生命周期详解
引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告 ...
- 【转】Java 类的生命周期详解
一. 引 言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大 ...
- 【转载】详解java类的生命周期
原文地址:http://blog.csdn.net/zhengzhb/article/details/7517213 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑, ...
- Java虚拟机(三)垃圾标记算法与Java对象的生命周期
前言 这一节我们来简单的介绍垃圾收集器,并学习垃圾标记的算法:引用计数算法和根搜索算法,为了更好的理解根搜索算法,会在文章的最后介绍Java对象在虚拟机中的生命周期. 1.垃圾收集器概述 垃圾收集器( ...
- [Java]类的生命周期(上)类的加载和连接[转]
本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 类加载器,顾名思义,类加载器(class loader)用来加载 Java 类到 Java ...
- JVM-类加载过程(Java类的生命周期)
什么是类加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的 ...
- Java对象的生命周期与作用域的讨论(转)
导读: Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 + T2 +T3.其中T1表示对象的创建时间,T2表示对 ...
随机推荐
- Persona——Web人物角色介绍
一.什么是人物角色? 人物角色,即persona([pə:’səunə]),这里讨论的主要是web persona,是指针对网站目标群体真实特征的勾勒,是真实用户的综合原型.我们对产品使用者的目标.行 ...
- HDUOJ----3342Legal or Not
Legal or Not Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- 【js】typeof与instanceof
typeof 运算符 返回一个用来表示表达式的数据类型的字符串. typeof[()expression[]] ; expression 参数是需要查找类型信息的任意表达式. 说明 typeof 运算 ...
- 使用DevExpress改变WinForm皮肤(VS)
基于步入DevExpress的使用(VS),进一步使用DevExpress改变WinForm皮肤,适合初学者. 提示: 1.对于DevExpress菜单中的RepositoryItemComboBox ...
- Linux内核(9) - 精华版 之 方法论
到目前为之,博客上分享的精华篇都可以归为方法论的范畴,在很多时候,都是方法论要比细节紧要得多.而这些精华篇又可细分为三个专题:Linux大史记:内核学习的方法论:驱动开发的方法论. Linux大史记 ...
- jdbc与odbc的差别,感悟,学习。。。
什么是JDBC? JDBC, 全称为Java DataBase Connectivity standard, 它是一个面向对象的应用程序接口(API), 通过它可訪问各类关系数据库.JDBC也是jav ...
- swagger and restful api 参考
http://git.oschina.net/redArmy/spring-cloud-books/blob/master/spring-cloud-provider-book/src/main/ ...
- asp.net2.0导出pdf文件完美解决方案【转载】
asp.net2.0导出pdf文件完美解决方案 作者:清清月儿 PDF简介:PDF(Portable Document Format)文件格式是Adobe公司开发的电子文件格式.这种文件格式与操作系统 ...
- python AES双向对称加密解密
高级加密标准(Advanced Encryption Standard,AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分 ...
- introduction to python for statistics,analysis笔记3
一.产生数组和矩阵 1.linspace(start,end,number),产生在start和end数之间number个数 >>> x = linspace(, , ) >& ...