《深入理解Java虚拟机》知识点目录
深入理解Java虚拟机
第二章 Java内存区域与内存溢出异常
2.2 运行时数据区域
- p42 Java内存区域划分概述
- p43 程序计数器
- p43 程序计数器是唯一一个不会存在OOM的内存区域
- p43 Java虚拟机栈
- p44 局部变量槽
- p44 本地方法栈
- p44 Java堆
- p45 分配缓冲区TLAB
- p46 方法区
- p46 永久代(持久代)
- p47 运行时常量池
- p47 直接内存
2.3 HotSpot虚拟机对象探秘
- p48 对象的创建
- p48 类加载检查
- p48 为新生对象分配内存
- p48 内存分配方式-指针碰撞
- p48 内存分配方式-空闲列表
- p48 空间压缩整理
- p48 清除算法
- p49 本地线程分配缓冲
- p49 Java虚拟机对对象进行必要的设置
- p51 对象的内存布局
- p51 对象头
- p51 对象头-对象自身运行时数据
- p51 对象头-类型指针
- p51 类型元数据
- p52 实例数据
- p52 对齐填充
- p52 对象的访问定位
- p52 句柄访问
- p52 直接指针访问
2.4 实战:OutOfMemoryError异常
-
p54 Java堆溢出
-
p55 堆的最小值参数 -Xms
-
p55 堆的最大值参数 -Xmx
-
p55 生成堆转储快照参数-XX:+HeapDumpOnOutOfMemoryError
-
p55 OutOfMemoryError异常-堆溢出
-
p55 内存映像分析工具
-
p55 堆内存溢出解决方案
-
p56 虚拟机栈和本地方法栈溢出
-
p57 StackOverflowError异常(请求的栈深度大于虚拟机所允许的最大深度)
-
p57 OutOfMemoryError异常-栈溢出(扩展栈时申请不到足够内存)
-
p57 栈内存容量参数 -Xss
-
p60 不断创建线程来产生OutOfMemoryError
-
p61 方法区和运行时常量池溢出
-
p61 String.intern()方法
-
p62 JDK7起,原本存放在永久代的字符串常量池被移至Java堆之中
-
p63 JDK6和JDK7及以后版本在字符串常量池实现上差异的示例
-
p64 制造方法区溢出-CGLib直接操作字节码运行时生成大量的动态类
-
p65 可能生成大量动态类,导致方法区溢出的场景
-
p65 HotSpot提供的元空间防御参数
-
p65 本机直接内存溢出
-
p65 参数 -XX:MaxDirectMemorySize
-
p66 直接内存导致的内存溢出的明显特征
第三章 垃圾收集器与内存分配策略
3.2 对象已死?
- p68 引用计数算法
- P70 可达性分析算法
- p70 GC Roots
- p70 引用链
- p70 可作为GC Roots的对象
- p71 再谈引用
- p71 Java引用按强度的四种分类(强引用、软引用、弱引用、虚引用)
- p72 生存还是死亡?
- p72 宣告对象死亡的两次标记过程
- p72 Finalizer线程
- p73 判断对象死亡的流程
- p73 finalize()方法只会被自动调用一次
- p74 回收方法区
- p74 方法区的垃圾收集主要回收两部分内容:废弃的常量和不再使用的类型
3.3 垃圾收集算法
- p75 垃圾收集算法
- p75 直接垃圾收集和间接垃圾收集
- p75 分代收集
- p75 分代假说(弱分代假说、强分代假说、跨代引用假说)
- p75 垃圾收集的一致设计原则
- p76 新生代和老年代
- p76 Minor GC(仅限于新生代的收集)、Full GC(面向整个堆的收集)
- p77 处理跨代引用的记忆集设计
- p77 分代相关名词的定义(分代种类)
- p77 标记-清除算法
- P78 标记-复制算法
- p79 Appel式回收(Eden、Survivor)
- p79 "逃生门"设计
- p79 标记-整理算法
- p79 移动式回收算法
- p80 吞吐量的实质是赋值器(用户程序)与收集器效率的总和
3.4 HotSpot的算法细节实现
- p81 根节点枚举
- p81 OopMap
- p82 安全点
- p82 安全点位置选取
- p82 抢先式中断和主动式中断
- p83 安全区域
- p84 记忆集和卡表
- p84 记忆集
- p84 卡表(记忆集的一种实现形式)
- p85 写屏障(在写的前后执行某种操作)
- p86 伪共享问题及其解决方案
- p87 并发的可达性分析
- p87 为什么必须在一个能保障一致性的快照上才能进行对象图的遍历
- p87 三色标记
- p88 "对象消失"问题的示意图
- p89 "对象消失"问题发生的充分必要条件(要求两条同时满足)
- p89 "对象消失"问题的两种解决方案:增量更新和原始快照SATB
3.5 经典垃圾收集器
- p90 HotSpot虚拟机的经典垃圾收集器关系图
- p91 Stop The World
- p90 Serial收集器
- p92 ParNew收集器
- p93 并发和并行
- p93 Parallel Scavenge收集器(一种以获取最大吞吐量为目的的收集器)
- p93 吞吐量指处理器用于运行用户代码的时间与处理器总消耗时间的比值
- p94 垃圾收集停顿时间指进行一次垃圾收集所需的时间
- p94 垃圾收集停顿时间缩短是以牺牲吞吐量和新生代空间为代价换取的
- p94 垃圾收集的自适应调节策略
- p94 Serial Old收集器
- p95 Parallel Old收集器
- p96 CMS收集器(一种以获取最短回收停顿时间为目的的收集器)
- p96 CMS收集器收集的四个步骤(初始标记-并发标记-重新标记-并发清除)
- p97 CMS三个明显缺点(对处理器资源敏感、无法处理浮动垃圾、大量空间碎片)
- p97 增量式并发收集器
- p97 浮动垃圾
- p97 并发失败
- p98 Garbage First收集器(G1收集器)
- p99 统一垃圾收集器接口
- p99 Mixed GC模式
- p99 G1开创的基于Region的堆内存布局
- p99 用于存储大对象的Humongous区域
- p99 具有优先级的区域回收方式实现
- p100 G1收集器的Region中存在的跨Region引用对象如何解决(跨代引用问题)
- p101 G1收集器的并发标记阶段如何保证收集线程与用户线程不干扰地运行
- p101 TAMS指针-解决并发标记、回收阶段的新对象创建问题
- p101 G1收集器怎样建立起可靠的停顿预测模型
- p101 衰减均值
- p101 G1收集器运作的四个步骤(初始标记-并发标记-最终标记-筛选回收)
- p102 用户指定期望的停顿时间是G1收集器很强大的一个功能
- p103 G1收集器与CMS收集器的比较
- p103 G1运作期间不会产生内存空间碎片
- p103 G1在维护卡表时不光需要使用写后屏障,为了实现SATB,还要使用写前屏障
- p103 G1中使用原始快照而不是增量更新的理由-减少并发标记和重新标记阶段的消耗
3.6 低延迟垃圾收集器
- p104 衡量垃圾收集器的三项重要指标(内存占用、吞吐量、延迟)
- p105 各款收集器的并发情况
- p105 低延迟垃圾收集器
- p105 Shenandoah收集器
- p106 Shenandoah与G1的三个不同之处(支持并发整理算法、不使用分代收集、放弃记忆集而使用连接矩阵)
- p106 Shenandoah收集器的工作过程(九个阶段)
- p108 Brooks Pointer
- p109 Brooks形式转发指针的多线程竞争问题
- p110 读屏障
- p111 引用访问屏障
- p112 ZGC收集器
- p112 ZGC的动态Region
- p113 染色指针技术
- p115 染色指针三大优势
- p116 多重映射
- p117 ZGC的运作过程(并发标记-并发预备重分配-并发重分配-并发重映射)
- p117 指针的自愈能力
- p118 ZGC不使用记忆集的优劣
- p119 "NUMA-Aware"内存分配
3.7 选择合适的垃圾收集器
- p121 Epsilon收集器
- p121 收集器的权衡
- p122 虚拟机及垃圾收集器日志
- p123 HotSpot功能日志参数-Xlog
- p123 虚拟机日志级别
- p124 如何通过虚拟机参数获得垃圾收集器过程的相关信息
- p127 垃圾收集器参数总结
3.8 实战:内存分配与回收策略
- p129 Java自动内存管理的根本目标(自动给对象分配内存、自动回收分配给对象的内存)
- p130 对象优先在Eden分配
- p130 内存空间分配担保机制(后面有更详细的解释p135)
- P131 大对象直接进入老年代
- p131 -XX:PretenureSizeThreshold参数(直接在老年代分配大对象)
- p132 长期存活的对象将进入老年代
- p132 对象年龄计数器
- p132 -XX:MaxTenuringThreshold参数(设置对象晋升到老年代的阈值)
- p134 动态对象年龄判定
- p135 空间分配担保
第四章 虚拟机性能监控、故障处理工具
4.2 基础故障处理工具
- p139 JDK中基础故障处理工具的三个分类
- p141 jps - 虚拟机进程状况工具
- p142 jstat - 虚拟机统计信息监视工具
- p143 jinfo - Java配置信息工具
- p144 jmap - Java内存映像工具
- p145 jhat - 虚拟机堆转储快照分析工具(JDK9后被弃用)
- p146 jstack - Java堆栈跟踪工具
- p146 线程快照
- p147 Thread类的getAllStackTraces()方法
- p148 JDK基础工具总结
4.3 可视化故障处理工具
- p152 JHSDB - 基于服务性代理的调试工具
- p157 JConsole - Java监视与管理控制台
- p160 线程长时间停顿的主要原因(等待外部资源、死循环、锁等待)
- p164 VisualVM - 多合一故障处理工具
此处因VisualVM未能成功安装而搁置
- p171 Java Mission Control - 可持续在线的监控工具(JMC和JFR)
- p171 Oracle Java SE Support 和 Oracle Java Advanced & Suite
- p174 飞行记录
4.4 HotSpot虚拟机插件及工具
- p176 HSDIS - JIT生成代码反汇编
- p179 JITWatch介绍
- p179 把日志输出到logfile文件
第五章 调优案例分析与实战
5.2 案例分析
- p182 大内存硬件上的程序部署策略
- p182 单体应用在较大内存硬件上的两种主要部署方式
- p183 使用单个Java虚拟机实例管理大内存需要考虑的问题
- p183 具备亲和性的集群
- p183 使用逻辑集群部署程序需要考虑的问题
- p184 集群间同步导致的内存溢出
- p184 JBossCache
- p185 堆外内存导致的溢出错误
- p187 外部命令导致系统缓慢
- p187 服务器虚拟机进程崩溃
- p188 不恰当数据结构导致内存占用过大
- p190 由安全点导致长时间停顿
- p191 处理器时间和时钟时间
- p192 可数循环和不可数循环
5.3 Eclipse运行速度调优
这里的可记录内容基本都在后面的章节有讲解,故不做整理
关注一下本章的5.3.x小节标题,这里调优Eclipse的过程可以视作一次简化的服务端调优过程,这里进行调优的顺序也有着参考价值
第六章 类文件结构
6.2 无关性的基石
-
p213 不同平台的Java虚拟机和它们统一支持的存储格式字节码是平台无关性的基石
-
p213 Java虚拟机只与Class文件这种特定的二进制文件相关联
-
p213 字节码指令所能提供的语言描述能力要比Java语言更加强大
6.3 Class类文件的结构
- p215 Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格紧凑排列
- p215 Class文件伪结构的两种数据类型:无符号数和表
- p215 Class文件中某一类型的“集合”
- p215 Class文件格式表
- p215 魔数与Class文件的版本
- p216 Java的版本号
- p218 常量池
- p218 Class文件常量池中的字面量和符号引用
- p219 动态连接
- p219 常量池的17种项目类型
- p220 UTF-8缩略编码
- p221 javap工具-用于分析字节码文件
- p223 常量池中的17种数据类型的结构总表
- p224 类和接口的访问标志
- p225 类索引、父类索引、接口索引集合
- p226 字段表集合
- p226 字段表结构
- p227 字段访问标志
- p227 方法和字段的描述符
- p227 描述符标识字符含义
- p229 方法表集合
- p229 方法表结构
- p229 方法访问标志
- p230 类构造器
()方法和 ()方法 - p230 重载
- p230 特征签名
- p231 属性表集合
- p231 虚拟机规范预定义的全部29种属性
- p233 属性表结构(attribute)
- p233 Code属性
- p233 Code属性表结构
- p234 变量槽
- p234 字节码指令
- p235 翻译字节码指令示例
- p236 Java中this关键字功能的实现
- p236 显示异常处理表(异常表)
- p237 Java异常和finlly处理机制在字节码层面的实现
- p239 Exceptions属性
- p239 LineNumberTable属性
- p240 LocalVariableTable及LocalVariableTypeTable属性
- p241 SourceFIle及SourceDebugExtension属性
- p241 ConstantValue属性
- p242 对static变量和普通变量赋值的不同
- p242 InnerClass属性
- p243 Deprecated及Synthetic属性
- p244 新的类型检查验证器
- p244 栈映射帧
- p245 Signature属性
- p245 Java使用擦除法实现伪泛型的好处和坏处
- p245 BootstrapMethods属性
- p247 MethodParameters属性
- p248 模块化相关属性
- p248 Module属性
- p249 exports属性
- p249 ModulePackages属性
- p249 ModuleMainClass属性
- p250 运行时注解相关属性
- p250 RuntimeVisibleAnnotations属性
- p250 annotation属性
6.4 字节码指令简介
- p251 操作码和操作数
- p251 Java虚拟机操作码的长度仅为一个字节
- p251 Java虚拟机解释器的伪代码模型
- p251 字节码与数据类型
- p252 操作码助记符
- p252 Java虚拟机指令集所支持的数据类型
- p253 加载和存储指令
- p254 运算指令
- p255 向最接近数舍入模式和向零舍入模式
- p255 NaN值
- p255 类型转换指令
- p255 宽化类型转换和窄化类型转换
- p256 对象创建与访问指令
- p257 控制转移指令
- P257 方法调用和返回指令
- p258 异常处理指令
- p258 同步指令
6.5 公有设计、私有实现
- p260 虚拟机在后台如何处理Class文件是自由的,在外部看起来和规范一致即可
- p260 虚拟机实现的两种主要方式
第七章 虚拟机类加载机制
- p262 虚拟机的类加载机制
7.2 类加载的时机
- p263 类的生命周期(加载->验证->准备->解析->初始化->使用->卸载)
- p263 有且只有六种情况导致类进行初始化
- p264 主动引用和被动引用
7.3 类加载的过程
- p267 加载
- p267 Java虚拟机在类加载阶段需要完成的三件事情
- p268 数组类创建过程中的规则
- p268 验证
- p268 验证的目的
- p269 验证阶段的四个检验动作
- p269 文件格式验证
- p269 元数据验证
- p270 字节码验证
- p270 停机问题
- p270 StackMapTable
- p271 符号引用验证
- p271 准备
- p271 准备阶段
- p272 JDK8之后,类变量随着对象一起存放在Java堆中
- p272 基本数据类型的零值
- p272 解析
- p272 解析阶段
- p272 符号引用
- p273 直接引用
- p273 17个需要先对符号引用进行解析的字节码指令
- p273 多次解析
- p274 解析动作针对的七类符号引用(八种常量类型)
- p274 类或接口的解析
- p274 类或接口解析的三大步骤
- p274 一个类拥有另一个类的访问权限,需其中之一成立的三条规则
- p275 字段解析
- p276 方法解析
- p276 接口方法解析
- p277 初始化
- p277 类的初始化阶段
- p277
()方法
7.4 类加载器
- p280 类加载器的定义
- p280 类与类加载器
- p280 每一个类加载器都拥有一个独立的类名称空间
- p281 双亲委派模型
- p281 Java虚拟机眼中的两种不同的类加载器
- p282 三层类加载器、双亲委派的类加载架构
- p282 启动类加载器
- p282 扩展类加载器
- p283 应用程序类加载器
- p283 类加载器的双亲委派模型
- p283 双亲委派模型的工作过程
- p284 双亲委派模型的实现
- p285 破坏双亲委派模型
- p285 双亲委派模型的三次被破坏
- p285 线程上下文类加载器
- p286 OSGi是如何通过类加载器实现热部署的
7.5 Java模块化系统
- p287 模块化的关键目标——可配置的封装隔离机制
- p287 Java的模块定义所包含的内容
- p288 模块的兼容性
- p288 类路径和模块路径
- p288 JAR文件和模块在类路径和模块路径的访问规则
- p290 OSGi与JPMS交互
- p290 模块化下的类加载器
- p290 扩展类加载器被平台类加载器取代
- p290 新版JDK取消jre目录
- p291 平台类加载器和应用程序类加载器都不再派生自URLClassLoader
- p291 jdk9以后三种类加载器各自负责的模块
第八章 虚拟机字节码执行引擎
- p293 虚拟机字节码执行引擎的概念模型
- p293 虚拟机字节码执行引擎的输入输出
8.2 运行时栈帧结构
- p294 栈帧的概念
- p294 当前栈帧和当前方法
- p294 虚拟机栈和栈帧的总体结构
- p294 局部变量表
- p294 局部变量表的概念
- p294 变量槽
- p295 Java中八种占用不超过32位存储空间的数据类型
- p295 reference类型
- p296 64位数据类型对变量槽的使用
- p296 局部变量表的索引定位
- p296 局部变量表的变量槽分配
- p299 操作数栈
- p299 栈帧的数据共享
- p300 动态连接
- p300 静态解析
- p300 动态连接
- p300 方法返回地址
- p301 附加信息
- p301 栈帧信息
8.3 方法调用
- p301 解析
- p302 解析的定义
- p302 方法调用字节码指令
- p302 非虚方法和虚方法
- p303 分派
- p303 静态分派
- p305 静态类型(外观类型)和实际类型(运行时类型)
- p305 重载时通过参数的静态类型而不是实际类型作为判断依据
- p307 类型模糊
- p308 动态分配
- p310 invokevirtual指令的运行时解析过程
- p311 Java语言中方法重写的本质
- p312 单分派与多分派
- p312 方法的宗量
- p314 Java语言是一门静态多分派,动态单分派的语言
- p314 虚拟机动态分派的实现
- p314 虚方法表
- p314 接口方法表
8.4 动态类型语言支持
- p316 动态类型语言
- p316 什么是动态类型语言
- p316 运行时异常和连接时异常
- p317 动态类型语言和静态类型语言的优缺点
- p317 Java与动态类型
- p318 java.lang.invoke包
- p319 方法句柄
- p319 方法句柄的基本用法
- p320 MethodHandle和Reflection的区别
- p321 invokedynamic指令
- p321 动态调用点
- p321 CONSTANT_InvokeDynamic_Info常量
- p324 实战:掌控方法分派规则
8.5 基于栈的字节码解释执行引擎
- p327 解释执行
- p327 编译过程
- p328 基于栈的指令集与基于寄存器的指令集
- p329 两种指令集的优缺点
- p329 基于栈的解释器执行过程
第九章 类加载及执行子系统的案例与实战
9.2 案例分析
- p335 Tomcat:正统的类加载器架构
- p336 功能健全的web服务器需要解决的问题
- p337 Tomcat服务器的类加载架构
- p338 OSGi:灵活的类加载器架构
- p339 OSGi(后续有详细讲解)
- p339 引入OSGi的理由
- p341 字节码生成技术与动态代理的实现
- p342 动态代理的简单示例
- p345 Backport工具:Java的时光机器
- p345 Retrotranslator和Retrolambd
9.3 实战:自己动手实现远程执行功能
尚未完成
第十章 前端编译与优化
10.1 概述
- p358 Java中的三种编译器
10.2 Javac编译器
- p359 Javac的源码与调试
- p361 Javac编译的一个准备过程和三个处理过程
- p362 解析与填充符号表
- p362 词法、语法分析
- p362 词法分析
- p362 标记
- p362 语法分析
- p363 填充符号表
- p363 符号表
- p363 注解处理器
- p364 轮次
- p364 语义分析与字节码生成
- p364 语义分析
- p365 标注检查
- p365 常量折叠
- p365 数据与控制流分析
- p366 解语法糖
- p366 语法糖
- p367 字节码生成
10.3 Java语法糖的味道
- p367 泛型
- p367 泛型的本质
- p368 Java与C#的泛型
- p368 类型擦除
- p369 泛型的历史背景
- p369 二进制向后兼容性
- p370 数组的协变
- p371 类型擦除
- p371 裸类型
- p374 Signature
- p374 值类型与未来的泛型
- p374 Valhalla
- p375 自动装箱、拆箱与遍历循环
- p377 条件编译
10.4 实战:插入式注解处理器
- p379 代码实现
- p379 注解处理器必须继承的抽象类AbstractProcessor
- p380 @SupportedAnnotationTypes注解和@SupportedSourceVersion注解
- p385 运行与测试
- p385 使用“-processor”参数来执行编译时需要附带的注解处理器
- p385 使用 -XprintRounds 和 -XprintProcessorInfor 参数来查看注解处理器运作的详细信息
第十一章 后端编译与优化
11.2 即时编译器
- p389 热点代码
- p389 即时编译器
- p389 解释器与编译器
- p389 解释器与编译器各自的优势
- p389 逃生门
- p390 罕见陷阱
- p390 逆优化
- p390 客户端编译器(C1编译器)和服务端编译器(C2编译器)
- p390 混合模式、解释模式、编译模式
- p391 分层编译
- p392 编译对象与触发条件
- p392 两类热点代码(被多次调用方法和被多次执行的循环体)
- p392 栈上替换
- p392 热点探测
- p393 两种主流的热点探测判定方式(基于采样的热点探测和基于计数器的热点探测)
- p393 方法调用计数器
- p393 方法调用计数器的衰减
- p393 方法统计的半衰周期
- p394 回边计数器
- p397 编译过程
- p397 客户端编译器
- p398 服务端编译器
11.3 提前编译器
- P405 提前编译的优劣得失
- p405 提前编译产品和对其研究的两个分支
- p407 三种即时编译器相对提前编译器的优势(性能分析制导优化、激进预测性优化、链接时优化)
11.4 编译器优化技术
- p411 优化技术概览
- p412 即时编译器优化技术一览
- p414 方法内联的两个主要目的(去除方法调用的成本、为其他优化建立基础)
- p414 冗余访问清除
- p415 复写传播
- p415 无用代码消除
- p415 方法内联
- p416 Java中虚方法无法内联的原因
- p417 类型继承关系分析
- p417 守护内联
- p417 内联缓存(单态内联缓存和超多态内联缓存)
- p417 逃逸分析
- p418 逃逸分析的基本原理
- p418 栈上分配
- p418 标量替换
- p418 标量和聚合量
- p418 同步消除
- p420 公共子表达式消除
- p420 公共子表达式
- p421 代数化简
- p421 数组边界检查消除
- p421 数组边界检查消除的概念和场景
- p422 隐式异常处理