JVM
2021-10-13 11:18:40 0 举报
AI智能生成
jvm总结
作者其他创作
大纲/内容
类加载机制
装载
1.通过类全名获取字节流
2.将字节流所代表的静态存储结构转化为方法区的运行时数据结构
方法区:类信息、静态变量、常量
3.在堆中生成对应的class对象,作为方法区中这些数据的访问入口
代表被加载类的
链接
验证
文件格式验证
验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,该验证的主
要目的是保证输入的字节流能正确地解析并存储于方法区之内。
要目的是保证输入的字节流能正确地解析并存储于方法区之内。
举例:版本号是否正确
这阶段的验证是基于二进制字节流进行的,只有经过该阶段的验证后,字节流才会进入内存的方法区中进行存储,后面
验证都是基于方法区的存储结构进行的。
验证都是基于方法区的存储结构进行的。
元数据验证
对类的元数据信息进行语义校验(其实就是对Java语法校验),保证不存在不符合Java语法
规范的元数据信息。
规范的元数据信息。
举例
是否继承了final类
一个非抽象类是否实现了所有的抽象方法
字节码验证
进行数据流和控制流分析,确定程序语义是合法的、符合逻辑的。对类的方法体进行校验分
析,保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为。
析,保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为。
举例
栈数据类型和操作码操作参数吻合(比如栈空间只有4个字节,但是我们实际需要的远远大于
4个字节,那么这个时候这个字节码就是有问题的)
4个字节,那么这个时候这个字节码就是有问题的)
符号引用验证
这是最后一个阶段的验证,它发生在虚拟机将符号引用转化为直接引用的时候(解析阶段),
可以看作是对类自身以外的信息(常量池中的各种符号引用)进行匹配性的校验。符号引用
验证的目的是确保解析动作能正常执行。
可以看作是对类自身以外的信息(常量池中的各种符号引用)进行匹配性的校验。符号引用
验证的目的是确保解析动作能正常执行。
举例
常量池中描述类是否存在
访问的方法或者字段是否存在且具有足够的权限
准备
为静态变量分配内存并且设置默认初始值
不包含final修饰的static,因为final在编译的时候就会分配了,准备阶段会显示初始化
治理不会为实例变量(也就是没加static)分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到java堆中
解析
把符号引用转为直接引用
符号引用就是一组符号来描述目标,可以是任何字面量。引用的目标并不一定已经加载到了内存中。 直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。
初始化
初始化阶段是执行类构造器()方法的过程。
内存模型
程序计数器
线程私有的,用于线程切换后能恢复到正确的执行位置
虚拟机栈
线程私有的,每个方法执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等
本地方法栈
本地方法用的
堆区
Young区
Eden区
新创建的对象会被分配到Eden区
不够内存分配给新对象时会触发MinorGC回收不活跃的对象
回收后空间还是不够就将部分活跃对象复制到Survivor区
Survivor区(S0+S1)
S区之所以分为S0和S1是为了避免出现内存碎片
当Eden区空间不够是会将活跃对象复制到Survivor区
Survivor区空间不够时将部分活跃对象复制到Old区
新生代中Eden:S1:S2为什么是8:1:1?
IBM公司的专门研究表明,新生代中的对象大概98%是 “朝生夕死”的
Old区
新创建的大对象会直接分配到Old区
Survivor区空间不够时将部分活跃对象复制到Old区
Old区内存不够时触发FullGC
方法区
方法区是被所有线程共享的内存区域,用来存储已被虚拟机加载的类信息、静态变量等
内存回收
垃圾收集算法
标记-清除
标记
找出内存中需要回收的对象,并且把它们标记出来
堆中所有的对象都会被扫描一遍,从而才能确定需要回收的对象,比较耗时
清除
清除掉被标记需要回收的对象,释放出对应的内存空间
缺点
标记和清除俩个过程都比较耗时,效率不高
会产生大量内存碎片,导致创建大对象时连续内存不够而提前触发另一次垃圾收集
标记-复制
将内存分为俩块相等的区域,每次只是用其中一块
当其中一块内存使用完了,就将存活的对象复制到另一块,然后把使用过的空间一次清除掉
缺点
空间利用率低
在对象存活率较高时就要进行较多的复制操作,效率会变低
如果不想浪费50%的空间没,就需要额外的空间进行分配担保,应对所有对象都有100%存活的情况,所以老年代一般不能直接选用这种算法
标记-整理
标记
找出内存中需要回收的对象,并且把它们标记出来
堆中所有的对象都会被扫描一遍,从而才能确定需要回收的对象,比较耗时
让所有存活的对象都向一端移动,清理掉边界以外的内存
分代收集算法
young区
复制算法
对象在被分配之后,可能生命周期比较短,Young区复制效率比较高
old区
标记清除或标记整理
Old区对象存活时间比较长,复制来复制去没必要,不如做个标记再清理
垃圾收集器
Serial
JDK1.3.1之前是虚拟机新生代收集的唯一选择
单线程收集齐,进行垃圾收集的时候需要暂停其它线程
优点
简单高效,拥有很高的单线程收集效率
缺点
收集过程需要暂停所有应用程序线程
算法
复制算法
使用范围
新生代
应用
Client模式下的默认新生代收集器
Serial Old
Serial Old收集器是Serial的老年代版本
也是一个单线程收集器,不同的是采用了标记-整理算法
ParNew
可以把这个收集器理解为Serial的多线程版本
优点
在多CPU时,比Serial效率高
缺点
收集过程暂停所有应用程序线程,单CPU时比Serial效率差
算法
复制算法
使用范围
新生代
应用
运行在Server模式下的虚拟机中首选的新生代收集器
Parallel Scavenge
Parallel Scavenge收集器是一个新生代收集器
它也是使用复制算法的收集器,又是并行的多线程收集器
看上去和ParNew一样,但是Parallel Scavenge更关注系统的吞吐量
吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)
吞吐量越大,垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序的运算任务
Parallel Old
Parallel Old是Parallel Scavenge收集器的老年代版本
使用多线程和标记-整理算法进行垃圾回收
也是更关注系统的吞吐量
CMS
CMS收集器是一种以获取最短回收停顿时间为目标的收集器
采用的是标记-清除算法,整个过程分为4步
1.初始标记
标记GC Roots直接关联对象,不用Tracing,速度很快
2.并发标记
进行GC Roots Tracing
3.重新标记
修改并发标记因用户程序变动的内容
4.并发清除
清除不可达对象回收空间,同时有新垃圾产生,留着下次清理称为浮动垃圾
整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的
优点
并发手机、低停顿
缺点
产生大量空间碎片、并发阶段会降低吞吐量,还会并发失败
background模式为正常模式执行上述的CMS GC流程
forefroud模式为Full GC模式
G1(Garbage-First)
G1收集器的堆内存布局与其它收集器有很大差别,G1将整个java堆划分为多个大小相等的独立区域(Region)
虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合
每个Region大小都是一样的,可以是1M到32M之间的数值,但是必须保证是2的n次幂
如果对象太大,一个Region放不下[超过Region大小的50%],那么就会直接放到H中
所谓Garbage-Frist,其实就是优先回收垃圾最多的Region区域
1.分代收集(仍然保留了分代的概念)
2.空间整合(整体上属于“标记-整理”算法,不会导致空间碎片)
3.可预测的停顿(比CMS更先进的地方在于能让使用者明确指定一个长度为M毫秒的时间片段内,消 耗在垃圾收集上的时间不得超过N毫秒)
工作过程
初始标记(Initial Marking)
标记以下GC Roots能够关联的对象,并且修改TAMS的值,需要暂 停用户线程
并发标记(Concurrent Marking)
从GC Roots进行可达性分析,找出存活的对象,与用户线程并发 执行
最终标记(Final Marking)
修正在并发标记阶段因为用户程序的并发执行导致变动的数据,需 暂停用户线程
筛选回收(Live Data Counting and Evacuation)
对各个Region的回收价值和成本进行排序,根据 用户所期望的GC停顿时间制定回收计划
0 条评论
下一页
为你推荐
查看更多