第七章 类的生命周期
1.类的生命周期:装载à连接(验证à准备à解析(可选))à初始化。
2.任何一个类的初始化都要求它的超类已经初始化,接口就不需要。
3.类在首次主动使用时初始化。
4装载过程:
通过全限定名获得二进制数据流
解析流为方法区的内部数据结构
创建一个代表该类型的CLASS类实例。
5.类装载器在预先装载时遇到缺失或错误的CLASS文件,它必须等到程序首次主动使用该类时才报告错误。
6.验证:在解析时需要验证,在装载时需要验证超类已被装载,在验证阶段结束后还需要有符号引用的验证,一般采用数据流分析器进行验证。
7.准备:分配内存,设置为默认初始值,即JAVA定义的默认值。
8解析:在类型的常量池中寻找类,接口,字段和方法的符号引用,并替换成直接引用。
9初始化:
为类变量赋予程序员设定的初始值
JAVA编译器为类初始化语句及静态初始化语句生成一个CLASS文件的<clinit>()方法,但如果没这些语句就不生成
定义为static final的常量不是在初始化时赋值。
10类实例化方式:
使用NEW
调用CLASS或者通过反射
调用现有对象的CLONE()方法
Java.io.ObjectInputStream的getObject()方法反序列化。
11.类实例初始化方式:针对不同的实例化方式,有不同的初始化方式
调用现有对象的CLONE()方法---虚拟机把原来被克隆的实例变量中的拷贝到新对象中
通过Java.io.ObjectInputStream的ReadObject()反序列化---通过输入流中读入的值来初始化那些非暂时性的实例变量
其它实例化方式虚拟机则调用对象的实例初始化方法(构造函数)。
12.如果构造方法通过明确地调用超类的构造方法(一个super()调用)开始,它CLASS中的<init>()方法会调用对应的超类<init>()方法。
13.如果类声明了一个名为finalize()的返回void的方法,垃圾收集器会在释放这个实例所占据的内存空间之前执行这个方法一次(最多一次)。
14.类与对象相似,都需要进行垃圾回收,否则方法区会不断增长。
15不可触及的:程序不再引用某类型。
16使用启动类装载器装载的类型永远是可触及的,只有用户定义的类装载器装载的类型才会变成不可触及的。
17.某一类型的CLASS实例可触及,则这个类的所有超类型的CLASS实例都是可触及的。
第八章 连接模型(忽略了很多细节,实际上挺重要的,以后有时间再研究)
1.编译JAVA程序后,每个类或者接口都有独立的CLASS文件,CLASS文件把它所有的引用符号保存在常量池中。每个CLASS文件都有一个常量池。
2.在程序运行的某个时刻,使用某个特定的符号引用时,先解析,解析过程就是根据符号引用查找到实体,再把符号引用替换成一个直接引用的过程,这个过程被称为常量池解析。
3.每个常量池入口都只被解析一次。
4.预先解析所有的符号引用,这样程序在它的main()方法尚未被调用的时候就已经完全连接了,这种方法被称为早解析。在访问每一个符号引用的最后一刻才去解析它,这种称为迟解析。何时解析依赖于实现。但抛异常总是看起来像迟解析,都是当使用到时才可能抛出。
5.在JAVA术语中,要求某个类装载器去装载一个类型,但是却返回了其他类装载器装载的类型,这种装载器被称为是那个类型的初始类装载器,而实际定义那个类型的类装载器被称为该类型的定义类装载器。
(书中P189开始至本章结束都未读过)
第九章 垃圾收集
1.垃圾收集器:回收不再被引用对象的内存,处理堆碎块。
2.垃圾收集好处:提高生产率,帮助程序保持完整性,不会因为错误释放内存而导致JAVA虚拟机崩溃。垃圾收集缺陷:加大影响程序性能,程序员无法控制何时进行垃圾回收。
3.垃圾收集算法首先检测出垃圾对象,其次回收垃圾对象所使用的堆空间并还给程序。
4.垃圾检测通常通过建立一个根对象的集合并且检查从这些根对象开始的可触及性来实现。
5.区分活动对象和垃圾的两个基本方法是引用计数和跟踪。
6.引用计数垃圾收集器通过为堆中的每一个对象保存一个计数来区分活动对象和垃圾对象,这个计数记录下了对那个对象的引用次数。是垃圾收集的早期策略。好处:执行速度快。坏处:无法检测出循环,每次引用计数的增加或减少都带来额外开销。这种策略现在已基本不用。
7.跟踪(标记并清除)收集器追踪从根结点开始的对象引用图,在追踪过程中遇到的对象以某种方式打上标记,当追踪结束时,未被标记的对象就是无法触及的。这种策略现在较可能使用。
8.标记并清除收集器通常使用压缩和拷贝两种策略来对付堆碎块。
9.压缩收集器:把活动的对象越过空闲区滑动到堆的一端,堆的另一端出现一个大的连续空闲区。被移动的对象的引用也被更新,指向新的位置。
10.拷贝垃圾收集器:把所有的活动对象移动到一个新的区域。拷贝过程中,他们被紧挨着布置,这样原有的区域被认为都是空闲区。好处:对象可以在从根对象开始的遍历过程中随着发现而被拷贝,不再有标记和清除的区分。
11.一般拷贝垃圾收集器这种算法称为“停止并拷贝”,一般把堆分为两个区域,任何时候都只使用其中的一个区域,直到这个区域被耗尽,此时,程序执行被中止,堆被遍历,遍历时遇到的活动对象被拷贝到另外一个区域,当停止和拷贝过程结束时程序恢复执行。内存将从新的堆区域中分配,直到它也被用尽。
12.简单的“停止并拷贝”收集器缺点:每一次收集,所有活动对象都必须被拷贝,一些具有非常长生命周期的对象会被不断拷贝。
13.按代收集器:通过把对象按照寿命来分组解决简单“停止并拷贝”收集器缺点。堆被划分为两个或者更多的子堆,每一个子堆为一“代”对象服务,最年幼的那一代进行最频繁的垃圾收集。如果一个最年幼的对象经历了好几次垃圾收集后仍然存活,这这个对象就成长为寿命更高的一代,即被转移到另外一个子堆中。年龄更高的每一代收集都没年轻一代来得频繁。
14.自适应收集器算法:监视堆中的情形,并且对应地调整为合适的垃圾收集技术。
15.渐进式收集算法使得垃圾收集的不确定时间能够限制在一定的范围之内,保证用户不会有明显的停顿感以及程序的实时性。渐进式收集采用每次发现并回收一部分的策略,通常是按代收集的收集器。通常年幼堆利用堆大小来保证收集器在一个最大时间值内渐进地收集所有对象,而最高寿的无法给定最大尺寸。
16.火车算法的目的是为了在成熟对象空间(最高寿)提供限定时间的渐进收集。大概过程(这里引用了不少原文)就是把成熟对象空间按编号分为几列火车,每列火车按编号分为几个车厢,收集器先检查最小号码火车是否为垃圾,如果是,回收整列火车,然后返回。如果全是垃圾,则只回收这列火车的最小号码的车厢,如果这个车厢中包含被外部车厢引用的对象,则把这些对象转移到其他车厢去,然后再回收这个车厢,并返回。保证整列火车没有循环的数据结构的关键是如何进行对象的移动。如果正被收集的车厢中有一个对象存在来自成熟对象空间以外的引用,这个对象被转移到正在被收集的火车之外的其他车厢去。如果对象被成熟对象空间的其他火车引用,对象就被转移到引用它的那列火车中去。然后转移过后的对象被扫描,查找对原车厢的引用。发现的任何被引用的对象都被转移到引用它的火车中区。新被转移的对象也被扫描,这个过程被不断重复,直到没有任何来自其他火车的引用指向正被收集的那节车厢。一旦没有从成熟对象空间外部来的引用,也没有从成熟对象空间内其他火车来的引用,那么这节正在被收集的车厢剩余的外部引用都是来自于同一列火车的其他车厢。算法把这样的对象转移到这节火车的最后一个车厢去。然后这些对象被扫描,查找对原被收集车厢的引用。任何新发现的被引用对象也被转移到同一列火车的尾部,也被扫描。这个过程不断重复,直到没有任何形式的引用指向被收集的车厢。然后算法归还整个最小数字车厢占据的空间,释放所有仍然在车厢内的对象,并返回。
目前SUN的Hotspot虚拟机使用的是火车算法。
17.记忆集合:一个数据结构,包还了所有对一节车厢或者一列火车的外部引用。火车算法常用。
18.垃圾收集器运行对象的终结方法,无法预测对象的终结方法何时运行。
19.引用对象:封装了指向其他对象的链接,被指向的对象称为引用目标,所有的引用对象都是抽象的java.lang.ret.Reference类的子类的实例。
20.对象状态:强可触及,软可触及,弱可触及,可复活的,影子可触及,不可触及。
接下来除了第二十章 线程同步 外,其他都是关于JAVA指令集的分析,暂时不看。