《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》读书笔记
2022-05-21 17:53:29 0 举报
AI智能生成
分代假说;jvm垃圾回收算法;java虚拟机工具;
作者其他创作
大纲/内容
1.标记出需要被回收的对象2.标记完成后然后进行统一回收3.也可以反过来标记存活的对象
1.执行效率不稳定
2.会产生大量的空间碎片
缺点:
1.标记清除
即半区复制1.将内存分为等大小的两块2.每次只使用其中的一块,等到这块使用完了,就将存活的对象复制到另一块上3.将使用过的那块,完全清除掉
1.不用考虑内存碎片的问题
优点
1.浪费一半空间
2.如果大部分对象都是存活的,就会产生大量的对象copy的成本
缺点
2.标记复制
1.标记:标记出存活的对象(标记过程与标记清除算法的标记过程一样)2.所有存活对象向内存一端移动3.直接清理掉边界以外的内存
3.标记整理
1.弱分代假说:绝大多数对象都是朝生夕灭的
2.强分代假说:熬过越多次垃圾收集,对象就越难以消亡
例如:在进行Minor GC时,这时年青代当中的部分对象被老年代引用,就不得不在年青代的GCRoot的基础上额外添加老年代的GCRoot
分代收集的难点:存在跨代引用
分代收集理论
根据“弱分代假说”和“强分代假说”可以推理出,存在互相引用的两个对象,更倾向于同生共死。例如:某个新生代存在跨代引用,由于老年代的对象难以消亡,新生代的这个对象同样得以存活,这样熬过多次minor GC后,同样得以晋升到老年代,跨代引用也就消除了
结论:依据这条假说,我们不必在每次minor GC时对整个老年代进行扫描,也不必浪费空间记录每一个对象是否存在跨代引用。只需在新生代创建一个全局的数据结构,称之为:“记忆集”,这个结构把老年代划分成若干个小块,标识出哪一块内存存在跨代引用,在minor GC时,将对应的对象加入GC ROOTS即可。
1.跨代引用相对同代引用只占极少数
跨代引用假说
1.常量
2.类静态引用
1.全局性引用
1.栈帧中的局部变量表
2.执行上下文
3.注意点:在根节点枚举时,会产生STW(stop the word)
可作为GC Roots的节点
长时间执行明显的特征就是:指令序列复用
方法调用、循环跳转、异常跳转都属于指令序列复用,都可以产生安全点
1.安全点选择的原则-基本都以\"是否具有让程序长时间运行\"为原则进行判定
2.安全点里记录了栈上,寄存器里哪些位置存放的是对象的引用
方便垃圾收集器开始扫描时,可以直接获取到对象的引用,而不用一个不漏的从GC Roots查找
3.作用
1.垃圾收集发生时,系统直接把所有的线程全部中断
2.发现有线程中断在不安全点上,就恢复该线程,等其运行到最近的安全点上再中断
3.几乎没有虚拟机采用抢先式中断
1.抢先式中断
1.当垃圾收集发生时,系统不主动操作用户线程,仅仅是设置一个简单的标志位
2.各执行线程在执行时会主动的不断去轮询这个标志位
3.当标志位为true时,线程就主动跑到最近的安全点上挂起
4.轮询标志和安全点是重合的
2.主动式中断
4.如何在垃圾回收时让所有的线程(不包括JNI调用的线程)都跑到最近的安全点
安全点
安全区域是指在一段代码片段中引用关系不会发生变化,在这个片段中任何位置开始垃圾收集都是安全的
何为\"安全区域\"?
只有获得cpu时间片的线程才有机会从不安全点运行到安全点。对于sleep或者blocked的线程,短时间内无法获得cpu时间片,系统也不可能一直等待它们。这是候就需要安全区域。
有了安全点,为何需要安全区域?
当用户线程运行到安全区域的代码时,会先标识自己进入安全区域了,当垃圾收集器开始工作时,就不用去管这些申明自己在安全区域的线程。当要离开安全区域时,用户线程必须先检查GC Roots 根是否已经枚举完成,如果完成了,就当做没事发生过一样,继续执行,否则必须等待GC Roots根枚举完成。
使用
安全区域
白色:表示对象尚未被垃圾收集器访问过在可达性分析刚刚开始的阶段,所有对象都是白色的,在可达性分析结束的时候,若对象仍为白色的,则代表该对象不可达
灰色:标识垃圾收集器已经访问过该对象,但对象上至少还存在一个引用未被垃圾收集器访问过
黑色:表示这个对象已经被垃圾收集器访问过,且对象上所有的引用都已经被扫描过黑色代表对象已经被扫描过,且它是安全存活的,如果有其他对象引用指向了黑色对象,无需再重新扫描一遍。黑色对象不能跨过灰色对象,直接指向白色对象
概念
所有对象都是白色的,只有GC ROOTS 是黑色的
1.初始状态
将所有GC ROOTS 直接引用的对象,标记为灰色
2.初始标记阶段
扫描整个引用链没有子节点的话,将本节点置为黑色有子节点的话,将本节点置为黑色,子节点置为灰色
3.并发标记
直至灰色对象没有其他子节点对象引用时结束
4.重复并发标记阶段
此时黑色对象时存活对象白色对象就是已消亡可回收的对象
5.扫描完成
扫描过程
在并发标记阶段时,用户线程和GC线程同时运行,会产生 多标和漏标 的情况
三色标记法缺陷
https://www.jianshu.com/p/d6d3a2adc50a
文章
三色标记法
垃圾回收算法
1.单线程收集器
2.serial收集器工作时必须暂停其他工作线程(STW)
特征
采用复制算法,暂停所有用户线程
1.新生代
2.老年代
工作机制
1.Serial收集器
1.实际ParNew收集器可以看成是Serial收集器的多线程并行版本
采用标记整理算法,暂停所有用户线程
2.ParNew收集器
1.Serial Old收集器是Serial收集器的老年代版本
3.Serial Old收集器
1.又称为“吞吐量优先收集器”
1.新生代收集器
2.基于标记复制算法实现
3.该收集器关注点不在垃圾收集时间的长短,而是整体达到一个可控制的“吞吐量”吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集器执行时间)
1.该值是一个大于0的毫秒数,设置后垃圾收集器将尽量保证垃圾收集的时间不超过用户设置的时间
2.该值并不是越小就越好,垃圾收集时间时间缩短是通过牺牲吞吐量和缩小新生代空间实现的,还会导致垃圾收集变得频繁
-XX:MaxGCPauseMillis 直接设置垃圾收集最大停顿时间
-XX:GCTimeRatio 直接设置吞吐量大小
垃圾收集器参数配置
4.Parallel Scavengae收集器
1.Parallel Scavenge收集器的老年代版本
2.支持多线程并发收集
1.基于标记整理算法实现
在注重吞吐量和处理器资源稀缺的场景下,可以考虑使用Parallel Scavenge + Parallel Old
5.Parallel Old收集器
1.CMS收集器是一款以获取最短GC停顿时间为目的的收集器
2.
1.基于标记清除算法实现
需要STW 这个过程仅仅只标记GC Root直接关联到的对象
1.初始标记
从GC Root直接关联的对象开始,并发的遍历整个对象图
2.并发标记
需要STW 这个过程是为了修正在并发标记过程中,因为用户程序继续运行,而导致标记变动的那部分对象的标记
3.重新标记
并发清理删判断为已经死亡的对象
4.并发清除
工作过程
1.并发收集
甚至一些官方文档又将CMS称为\"并发低停顿收集器\"
2.低停顿
1.对处理器资源非常敏感
也就是在4个处理器及以上的场景中,并发时,最多占用不超过25%的处理器资源,并且随着处理器数增加而下降
但当处理器数目不足4个时,对用户线程的影响将变得很大
2.CMS默认的回收线程数=(处理器数+3)/4
有可能导致“font color=\"#c41230\
3.无法处理“浮动垃圾”
6.CMS收集器
G1收集器
垃圾收集器
列出虚拟机正在运行的进程
用途
jps [options] [hostid]
命令格式
只输出font color=\"#c41230\
-q
输出虚拟机进程启动时传递给主函数main()的参数
-m
输出主类的全名,如果运行的是jar包,则输出jar包的全路径
-l
输出虚拟机进程启动时的jvm参数
-v
输出通过flag文件传递到JVM中的参数
-V
参数
jps
虚拟机统计信息监控工具
ps1:如果是本地虚拟机进程,则VMID和LVMID一致
ps2:如果是远程虚拟机,则VMID的格式为:[prptocol:][//]lvmid[@hostname[:port]/servername]
jstat [option vmid [ interval [s|ms] [count] ] ]
查看进程2958的gc信息,每隔250ms打印一次,共10次
jstat -gc 2958 250ms 10
实例
监视gc信息
-gc
监控类的加载,卸载,总空间及类装载耗时
-class
监视内容与-gc基本相同,但输出主要关注java堆各个区域使用到的最大最小空间
-gccapacity
监视内容与-gc基本相同,单输出主要关注百分比
-gcutil
在-gcutil的基础上,增加上一次gc的原因
-gccause
监视新生代垃圾收集情况
-gcnew
与-gcnew基本相同,额外关注最大最小空间
-gcnewcapacity
监视老年代垃圾收集情况
-gcold
与gcold基本相同,输出关注使用到的最大最小空间
-gcoldcapacity
输出永久代最大最小空间
-gcpermcapacity
输出及时编译器编译过的类和耗时信息
-compiler
输出及时编译器编译过的方法
-printcompilation
jstat
查看和调整虚拟机的各项参数
jinfo [option] pid
-flag [+|-] name
运行期修改一部分运行期可修改的虚拟机参数值
-flag name=value
jinfo
1.用于生产堆转储快照(Heap Dump)
2.查询finalize 的执行队列
jmap [option] vmid
生成java堆转储快照
-dump
显示在F-queue队列中等待finalize线程执行finalize方法的对象
-finalizerinfo
显示java堆信息,如使用哪种回收器,参数配置,分代状况等
-heap
显示堆中对象统计信息,包括,类,实例数量,合计容量
-histo
以classloader为统计口径,显示永久代内存状况
-permstat
当虚拟机进程对-dump没有响应时,可以使用-F强制生成快照
-F
jmap
虚拟机转储快照分析工具
jhat会启动一个内置的http服务器
jhat 转储的dump文件
jhat
java堆栈跟踪工具
用于生成虚拟机的线程快照
jstack [option] vmid
当正常输出线程快照的命令不被响应时,使用-F强制输出线程快照
除堆栈外显示关于锁的额外信息
如果调用本地方法的话,可以下手C/C++堆栈
jstack
jcmd 进程id GC.run
jvm命令强制垃圾回收
虚拟机排查工具
ps:一个class文件对应着一个唯一的类或者接口定义信息,但是反过来说,类或接口却不一定得定义在文件里,可以动态生成,直接送入类加载器
ps2:class文件是一个以8个字节为基础单位存储的二进制流
前置说明
由多个无符号数或者其他表构成的复合数据类型,通常以 _info 结尾
表
类型 名称 数量
前四个字节为固定魔数 0xCAFEBABY
魔数的唯一作用就是用来标识这个class文件是否是能被java虚拟机接受
u4 magic 1
子版本号
u2 minor_version 1
高版本的jdk能向下兼容低版本的class文件,但不能运行以后的java版本
主版本号
u2 major_version 1
常量池的大小
u2 constant_pool_count 1
常量池表
cp_info constant_pool constant_pool_count-1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interface_count interfaces_count
u2 field_count 1
field_info fields field_count
u2 methods_count 1
methods_info methods methods_count
u2 attributes_count 1
attributes_info attributes attributes_count
文件结构内容
Class类文件结构
1.通过类的全限定名获取定义此类的二进制流
2.将这个二进制流所代表的静态存储结构转换为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区的这个类的各种数据访问的入口
1.加载
确保Class文件包含的字节流符合java虚拟机规范,保证这些信息被当成代码运行后不会危及虚拟机自身的安全
1.文件格式验证
2.元数据验证
3.字节码验证
4.符号引用验证
2.验证
1.为类中定义的类变量(静态变量)分配内存并赋初始值
2.此时赋的值时零值
3.准备
4.解析
5.初始化
6.使用
7.卸载
1.顺序
其中只有:加载、验证、准备、初始化、卸载这5个操作的顺序是固定的
2.固定顺序
验证、准备、解析三个阶段又称为链接
3.链接
class的加载机制
jvm
0 条评论
回复 删除
下一页