代码拉取完成,页面将自动刷新
267
1. JAVA虚拟机执行引擎:
1> 一次性解释字节码 ==> 慢
2> 即时编译器(第一次执行的字节码会被编译成本地机器代码, 编译出的本地机器代码会被缓存) ==> 占用内存多
3> 自适应优化(记录使用最频繁的代码段,加入缓存)
2. 空指针, 数组下标越界, 垃圾回收机制等, 都是保证java内存安全的机制
3. java的缺点: 内存管理和线程调度
1> 内存管理: 垃圾回收机制的不可控性
2> 最小公分母问题: 由跨平台引起的, 如java, GUI编程
4. 在编写平台独立的java程序时,还必须遵从两条原则:
1> 不要依赖及时终结(finalization)来达到程序的正确性
2> 不要依赖线程优先级(thread prioritization)来达到程序的正确性
这两条原则可以防止java虚拟机规范中允许的垃圾收集和线程在不同实现中的变化所带来的不利影响
5. 组成java安全沙箱的基本组件
1> 类装载器结构
2> class文件检验器
3> 内置java虚拟机(及语言)的安全特性
4> 安全管理器及java API
6. class文件检验器要进行四趟独立的扫描来完成它的操作
1> class文件的结构检查:
第一次扫描的主要目的就是保证这个字节序列正确的定义了一个新的类型,
它必须遵从java class文件的固定格式,这样它才被能编译成在方法区中的内部数据结构
2> 数据类型的语法检查:
确认他们是否是所属类型的实例
3> 字节码验证
java虚拟机对字节流进行数据流分析, 这些字节流(操作码的单字节指令组成的序列)代表的是类的方法
栈帧其实就是一个内存片段,其中存储着局部变量和计算的中间结果
第一趟, 第二趟, 第三趟扫描中, class文件检验器可以保证导入的class文件构成合理,内在一致,符合java编程语言
的限制条件,并且包含的字节码可以被java虚拟机安全的执行
4> 符号引用验证
class文件检测器的第四趟扫描仅仅是动态连接过程的一部分,
动态连接是一个将符号引用解析为直接引用的过程
7. java安全模型的组成部分:
1> 类装载器体系结构
2> class文件检验器
3> java中内置的安全特性
4> 安全管理器
8. 拒绝服务(DOS):
1> 不断分配内存直到内存耗尽
2> 不断生成线程导致每件事都满的不可忍受
9. 虚拟机内部通常使用守护线程, 而main()方法是非守护线程.
10. 每个java虚拟机实例都有一个方法区以及一个堆, 他们是由该虚拟机实例中所有线程共享的
11. java栈是由许多栈帧组成, 一个栈帧包含一个java方法的调用状态, 当线程调用一个java方法时, 虚拟机压入 一个
新的栈帧到该线程的java栈中, 当该方法返回时, 这个栈帧被从java栈中弹出并抛弃
12. 方法区:
1> 存储类型的信息: 类型的全限定类名, 直接超类的全限定类名, 类型的访问修饰符, 类型是接口还是类,
任何直接超接口的全限定类名的有序列表
2> 该类型的常量池, 字段信息, 方法信息, 除了常量以为的所有静态变量,
3> 字段信息: 字段在类或接口中声明的顺序, 字段名, 字段类型, 字段修饰符
4> 方法信息: 方法在类或接口中声明的顺序, 方法名, 方法参数的数量和类型(按声明顺序), 方法的修饰符
5> 如果方法不是抽象和本地方法: 方法字节码, 操作数栈和该方法栈帧中的局部变量区的大小, 异常表
6> 静态变量: 他们总是作为类型信息的一部分而存储在方法区
7> 编译时常量(就是那些用final声明的, 用编译时已知的值初始化的类变量):
每个使用编译时常量的类型都会复制它的所有常量到自己的常量池中或嵌入到它的字节码流中
8> 指向ClassLoader类的引用: 如果是用户类装载器装载的, 那么虚拟机必须在类型信息中存储对该类装载器的引用,
这是作为方法表中的类型数据的一部分保存的
9> 指向Class类的引用: 每个被装载的类型, 虚拟机都会相应的为它创建一个java.lang.Class类的实例(反射)
10> 方法表: 存储在方法区中的,类型信息的数据结构, 提高访问效率.
虚拟机对每个装载的非抽象类, 都生成一个方法表
13. 堆:
1> java程序在运行时创建的所有类实例或数组都放在同一个堆中, 一个java虚拟机实例中只存在一个堆空间
14. 对象(对象中通常有一个指向方法区的指针):
每个对象的数据都包含一个指向特殊数据结构的指针, 这个数据结构位于方法区, 它包括两部分:
1> 一个指向方法区对应类数据的指针
2> 此对象的方法表
15. 方法表:
方法表是个指针数组, 其中每一项都是一个指向"实例方法数据"的指针, 实例方法数据包括以下信息:
1> 此方法的操作数栈和局部变量去的大小
2> 此方法的字节码
3> 异常表
16. 栈帧(栈帧由三部分组成):
1> 局部变量区
2> 操作数栈
3> 帧数据区
17. 在源代码中, byte, short, char, boolean在局部变量区都被转换成了int, 在操作数栈中也一样
18. 栈中永远不会发现对象的拷贝, 只有对象的引用
20. class文件终结符:
B byte
C char
D double
F float
I int
J long
S short
Z boolean
V void
L或; 对象类型
[ 数组类型终结符, [ 一维数组, [[ 二维数组, java数组最多只有255维
21. 类型的装载, 连接和初始化:
java虚拟机通过装载, 连接和初始化一个java类型, 使该类型可以被正在运行的java程序所使用
a> 装载: 把二进制形式的java类型读入到java虚拟机中
要装载一个类型, java虚拟机必须
1> 通过该类型的全限定类名,产生一个代表该类型的二进制数据流
2> 解析这个二进制数据流为方法区内的内部数据结构
3> 创建一个表示该类型的java.lang.Class类的实例
b> 连接: 把已经读入的虚拟机的二进制形式的类型数据合并到虚拟机的运行状态中去
1> 验证: 确保了java类型数据格式正确并且适用于java虚拟机
对于字节码流的验证, 可以通过一次性使用一个数据流分析器进行验证, 在连接过程中一次性验证字节码流,
而非在程序执行时动态验证, 提高运行速度
2> 准备: 为类型分配它所需要的内存
在准备阶段, 虚拟机把给类变量分配的内存根据类型设置为默认值
3> 解析: 把常量池中的符号引用转换为直接引用(可以在虚拟机真正使用符号引用时去执行)
c> 初始化: 给类变量赋予适当的初始化值, 必须在每个类或接口首次主动使用时初始化
以下六种情况属于主动使用:
1> 当创建某个类的新实例时
2> 当调用某个类的静态方法时
3> 当使用某个类或接口的静态字段时, final修饰的静态字段除外, 它被初始化为一个编译时的
常量表达式
4> 当调用java API中的某些反射方法时, 比如类Class中的方法或者java.lang.reflect
包中的类的方法
5> 当初始化某个类的子类时
6> 当虚拟机启动时某个被标为启动类的类(含有main()方法的那个类)
为类型的静态变量设置初始化值:
称为初始化方法, 在class文件中, 这个方法被称为<clinit>, 这个方法只能被虚拟机调用
初始化一个类包括两个步骤(超类总是在子类之前被初始化):
1> 如果类存在直接超类, 且未被初始化, 先初始化直接超类
2> 如果类存在类初始化方法, 就执行此方法
初始化接口只需要一步:
1> 如果接口存在接口初始化方法, 就执行此方法
java虚拟机必须保证初始化过程的同步, 如果多线程需要初始化一个类, 仅仅允许一个线程来执行初始化
<clinit>方法:
1> 类变量初始化语句, 和静态初始化语句(静态代码块)组成, 按照声明的顺序执行
2> 如果没有声明类变量,也没有静态初始化语句就不会有<clinit>方法
3> 声明了类变量, 但未显示初始化(包括在静态代码块中初始化), 就没有<clinit>方法
4> final修饰的类变量且此变量使用常量表达式初始化, 也不会有<clinit>方法
eg:
a> static final int = 5; 无<clinit>方法
b> static final int = (int)(Math.random() * 0.5); 有<clinit>方法
22. 只有在某个接口所声明的非常量字段被使用时, 该接口才会被初始化,
而不会因为实现这个接口的子接口或类要初始化而被初始化
23. 如果类装载器在预先装载时遇到一个缺失或错误的class文件, 它必须等到程序首次主动使用该类时才报错,若未使用,
就不会报错
24. 实例化一个类有四种途径:
1> 明确的使用new操作符
2> 调用Class或者java.lang.reflect.Constructor对象的newInstance()方法
3> 调用任何现有对象的clone()方法
4> 通过java.io.ObjectInputStream类的getObject()方法反序列化
25. 一个<init>()方法可能包含三种代码:
1> 调用另一个<init>()方法
2> 实现对任何实例变量的初始化
3> 构造方法体的代码
如果构造方法调用同一个类的另一个构造方法(通过this()), 它对应的<init>()方法由两部分组成:
1> 一个同类的<init>()方法
2> 实现了对应构造方法的方法体的字节码
普通的构造方法, 未调用同类的构造方法:
1> 一个超类的<init>()方法的调用
2> 任意实例变量初始化方法的字节码
3> 实现了对应构造方法的方法体的字节码
26. 常量池:
1. 常量池中保存的数据
a> 字面常量
b> 类和接口的权限定类名
c> 字段的名称和描述符
d> 方法的名称和描述符
注:
字段 ==> 类或接口的实例变量或类变量
字段描述 ==> 指示字段类型的字符串
方法描述 ==> 指示方法的返回值和参数的数量, 顺序和类型
2. Class文件引用符号
每个class文件有一个常量池, 每一个被虚拟机装载的类或接口都有一份内部版本的常量池, 称作运行时
常量池. 当一个类型首次装载时, 所有来自于类型的符号引用都装载到了类型的运行时常量池
3. 常量池解析
如果某个特定的符号引用将要被使用, 它首先要被解析. 解析的过程就是根据符号引用查找实体,
再把符号引用替换为直接引用的过程, 因为所以的符号引用都保存子在常量池中, 所以这个过程常被称为
常量池解析
1> 早解析:
预先解析所有的符号引用, main()尚未被调用时, 就已经完全连接
2> 迟解析:
java虚拟机在执行程序第一次用到这个符号引用时才去解析它
实现java虚拟机规范时,也可以使用两种极端情况之间的折中解析策略
对于特定的虚拟机, 无论何时进行解析, 都在第一次实际试图访问符号引用时, 才抛出错误,
如果程序不使用这个类, 错误永远不会被抛出
27. 类型的卸载:
1> 使用启动类装载器装载的类型永远是可触及的, 所以永远不会被卸载, 只有用户自定义的类装载器
装载的类型才会变成不可触及的, 从而被虚拟机回收
28. forName()方法详解:
1> 只有一个参数的forName()方法:
它使用当前的类装载器装载, 即装载forName()方法的类装载器装载
并总是初始化该类型
2> 有三个参数的forName()方法(forName(String name, boolean initialize, ClassLoader loader) ):
1> loader为类装载器
2> initialize 为true时, 类型会在forName()方法返回前被连接并初始化
为false时, 类型会被装载, 可能会被连接, 但不会被forName(), 方法明确地初始化
如果类型在调用forName()方法前已经被初始化,
即使为false, forName()方法返回的类型也已经被初始化了
29. 双亲委派模型
1> 用户自定义类装载器在创建时被分配一个"双亲"类装载器, 如果没有显示的传递一个双亲类装载器给
用户自定义类装载器, 系统类装载器就默认被指定为双亲
2> 双亲委派模型会逐层向上委派, 故无论此类装载器的双亲是否是系统类装载器,
类的装载都是最先在系统类装载器中查找的
30. 术语"当前命令空间"表示当前类装载器的命名空间
31. 垃圾收集算法
1> 引用计数法
堆中的每个对象都有一个引用计数, 没有一个引用指向该对象, 计数加1
任何引用为0的对象, 可以被垃圾收集
2> 追踪算法("标记并清除")
从根节点开始追踪对象, 遇到对象之后标记, 最终没被标记的对象, 将被垃圾收集
3> 压缩收集器
4> 拷贝收集器
5> 按代收集的收集器
简单拷贝收集器浪费效率的一个主要原因就是, 它们每次都把这些生命周期很长的对象
来回拷贝, 消耗大量的时间. 按代收集器通过把对象按照寿命来分组解决这个效率低下的问题
6> 自适应收集器
在不同的情况下, 使用不同的垃圾收集器算法, 以提高效率
7> 火车算法
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。