jvm知识点
2020-06-16 10:27:18 2 举报
jvm
作者其他创作
大纲/内容
自定义类加载器User-Defined ClassLoader
源代码
解析Resolve
CMS(Concurrent Mark Sweep)收集器
方法的退出包括两部分:一部分是遇到方法正常结束的指令退出;另一部分是方法遇到异常时退出。方法在退出之后都需要返回到该方法被调用的位置。方法的退出对应于栈帧的出栈过程。过程是,恢复上层方法的局部变量表和操作数栈,把该方法返回值亚茹调用者的操作数栈,调用程序计数器执行后面的指令。
需要满足以下三个条件:- 该类所有的实例都已经被回收,即堆中不存在该类的任何实例- 加载该类的ClassLoader已经被回收- 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法JVM可以对满足上述三个条件的无用类进行回收,这里仅仅是”可以\
操作数栈
字节码生成器
动态链接
Student1
iload_1
本地方法库Native Method Library
32位长度(4b)
标记-清除算法\t\t\t减少回收停顿时间\t\t\t碎片 -XX:CMSInitiationgOccupancyFraction \t\t\tConcurrent Mode Failure 启用Serial Old
垃圾回收器Garbage Collection
栈帧(sum)
JAVA栈本地变量表
到对象类型数据的指针
复制算法(Copying)
S0From Space
int
对象类型数据
Serial
本地方法栈(Native Method Stack)
解析2.3
short
young都是复制回收
1.8之前叫永久带(HotSpot)
其实是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等)和Serial收集器完成一样,是许多运行在Server模式下虚拟机的首要选择,除了Serial收集器外,只有它能与CMS收集器配合工作
Parallel Scavenge收集器
1,句柄java堆中划分出一块内存作为句柄池,reference中存储的是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。句柄访问最大的好处就是reference中存储的是稳定的句柄地址,在对象被移动时,只用修改句柄中的实例数据指针,而reference本身不需要修改!
Class文件
堆Heap
执行引擎Execution engine
老年代(老年代对象存活率高,使用标记-整理算法回收垃圾对象,当新生代的对象经历了15次的轻GC或新new一个大对象的时候对象便会进入老年代,若老年代满了会触发FullGC,系统会暂时停止,JVM调优调的就是减少FullGC的发生次数)
默认
程序计数器(PC寄存器)Program Counter Register (记录当前线程执行到的字节码的行号)
注解抽象语法树
Old
局部变量表
执行引擎Execution Engine
Major GC
初始化3
线程独占区
程序计数器(Program Counter Register)
拓展类加载器Extension ClassLoader
token流
reference
本地方法栈Native Method Stack(JVM调用本地方法)
Eden(对象出生的地方)
词法分析器
引导类加载器BootStrap ClassLoader
common
S1To Space
Parallel Old
栈帧(common)
栈帧(main)
解释器Interpreter
堆垃圾回收前的第一步就是要判断哪些对象可以被回收,即不能再被任何途径使用的对象
Student实例
方法出口
G1
float
Thread隔离区
中间代码生成器
Young Gen (-Xmn)
初始化Initialization
目标代码生成器
(存储运行时常量池、已被虚拟机加载的类信息、常量、静态常量、即时编译后的代码等数据 )
程序计数器
本地接口(JNI)Native Method Interface
虚拟机栈(VM Stack)
卸载5
虚拟机为对象分配内存
方法区(Method Area)
运行时数据区Runtime Data Area
验证Verify
Parallel Old收集器
连接2
Serial Old(MSC)
基本类型
元空间(永久代。JDK1.8之后就变成本地内存了)
Old区
元空间
实例化 new
新生代(新生代GC时采用的算法是复制算法,当有一个新对象产生时会存在于Eden,s0与s1两个区总会有一个区是空白的,当经历垃圾回收时,会将尚且存活的对象复制到空白的那个区,然后清除另外一个区)
-XX:MaxPermSize
探测器
类加载器ClassLoader
到对象实例数据的指针
语法树/抽象语法树
From(s0)
类就是一个模板对象是具体的
一个方法一个栈帧
getClassLoader
5
准备Prepare
Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法,在注重吞吐量以及CPU资源的场合都可以优先考虑Parallel Scavenge收集器和Parallel Old收集器
将分配的内存初始化为零值
存储对象实例
向上委托
对象引用(引向E)
元空间/方法区 Meta Space
本地方法栈
编译器(Just-in-time Compiler)
变量压栈
Minor GC
虚拟机栈VM Stack(存储栈帧)
实例池
逃逸分析:就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。-XX:+DoEscapeAnalysis//使用-XX:-DoEscapeAnalysis//不用使用逃逸分析,编译器可以对代码做如下优化:一、同步省略。如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。二、将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。(栈上分配--Hotspot并没有实现真正意义上的栈上分配,实际上是标量替换)三、分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。在动态编译同步块的时候,JIT编译器可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果同步块所使用的锁对象通过这种分析被证实只能够被一个线程访问,就是优化成锁消除。
JAVA堆
Young
局部变量表基本数据类型会直接存值,引用数据类型会存放对象的引用
验证2.1
语法分析器
JVM Heap (-Xms -Xmx)
3
1、加载类文件 从class文件或者jar中,或者从二进制流中以类全名标识存入方法区,供之后的使用。2.1、验证类文件是否符合jvm的规范,验证一些类的基本信息,如格式验证、语义分析、操作验证。2.2、准备为类的静态变量和常量分配空间和初始值,在堆中分配空间。2.3、就是把将常量池中的符号引用转为直接引用,可以认为是一些静态绑定的会被解析;动态绑定则只会在运行是进行解析; 静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写)。3、初始化将一个类中所有被static关键字标识的代码统一执行一遍,如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是<clinit>方法,即类/接口初始化方法。该方法的作用就是初始化一个中的变量,使用用户指定的值覆盖之前在准备阶段里设定的初始值。任何invoke之类的字节码都无法调用<clinit>方法,因为该方法只能在类加载的过程中由JVM调用。如果父类还没有被初始化,那么优先对父类初始化,但在<clinit>方法内部不会显示调用父类的<clinit>方法,由JVM负责保证一个类的<clinit>方法执行之前,它的父类<clinit>方法已经被执行。JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程
标记整理
VM栈
double
ClassLoader
iload_0
JVM运行时数据区
引用计数法
G1(Garbage-First)收集器
-优先分配Eden区•大对象直接分配到老年代-XX:PretenureSizeThreshold• 长期存活的对象分配老年代-XX:MaxTenuringThreshold=15• 空间分配担保-XX:+HandlePromotionFailure检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小。• 动态对象年龄对象如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代-XX:TargetSurvivorRatio
Student3
Virtual-伸缩区
垃圾回收
老年代 Old Space
垃圾收集器系统会在空闲的时候执行gc操作也可以手动使用System.gc();来通知虚拟机执行GC。但这个并不会马上被虚拟机执行,虚拟机会在其空闲的时候执行GC操作(为什么新生代对象进入老年代需要经历15次GC,因为对象头里面用了四位记录GC状态1111 = 15)
调用
main
本地方法接口(JNI)
垃圾收集器
对象实例数据
通过句柄访问对象
对象引用:就是通过栈帧中局部变量表所存储的对象引用来对堆内存中的对象实例进行访问或操作的!简单点理解就是栈帧中有个对象引用的指针,通过各种方法指向了堆内存中的对象实例。
若未找到引用,则执行类的加载,加载,验证,初始化
最基本、最悠久的垃圾收集器,是一个单线程收集器。只使用一个线程去完成垃圾收集工作,在垃圾收集时,必须暂停其它所有的工作线程(Stop The World),直到它收集结束。相比于其它垃圾收集器,Serial收集器由于没有线程交互的开销,自然可以获取很高的单线程收集效率,对于运行在Client模式下的虚拟机来说是个不错的选择。
如何判断一个类是无用的类
是一款面向服务器的垃圾收集器,蛀牙针对配备多颗CPU及大容量内存的机器,以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。被视为JDK1.7中HotSpot虚拟机的一个重要进化特征。特点如下:- 并行与并发: G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU来缩短停顿时间。- 分代收集: 虽然G1可以不需要其它收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。- 空间整合: 与CMS的标记-清理算法不同,G1从整体来看是基于\"标记-整理\"算法来实现的收集器;从聚不上来看是基于”复制“算法实现的- 可预测的停顿: 相对于CMS的一大优势,能让使用者明确指定在一个长度为M毫秒的时间片段内G1的收集步骤: 初始标记 并发标记 最终标记 筛选回收G1收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的Region。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)官方推荐G1
标记-整理算法(Mark-Compact)
来回换
首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象。缺点: - 效率问题,标记和清除两个过程的效率都不高 - 空间问题,标记清除后会产生大量不连续的碎片
类装载子系统
新生代: 每次垃圾收集时都有大批对象死去,只有少量存活,选中复制算法老年代: 对象存活率高,没有额外的空间对它进行分配担保,使用标记清理/整理算法
可达性分析算法
Eden(伊甸园)
分代收集算法
概述:凡是无法和”GC ROOTS“建立直接或间接联系的对象都可判定为垃圾。基本思想:通过一系列成为”GC ROOTS“的对象作为起点,从这些节点向下搜索,节点所走过的路径称为引用链,当一个对象到GC ROOTS没有任何引用链相连的话,则证明此对象是不可用的。GC ROOTS根节点: VM栈的本地变量表中引用的对象,静态属性、常量引用的对象,本地方法栈引用的对象等
系统类加载器Application ClassLoader
新生代Young Space
卸载
CMS
线程共享区
标记-清除算法(Mark-Sweep)
调用对象的 init 方法
方法区
javac 编译
存活区-Survivor
ParallelScavenge
class文件
对象的访问
new 类名()
把内存分为大小相同的两块,每次只使用其中的一块,当这一块的内存使用完后,将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉,保证内存的连续可用。缺点:导致内存浪费,只能利用一半。
代码优化器
Linking链接
使用
是一种以获取最短回收停顿时间为目标的收集器,非常符合在注重用户体验的应用上使用。是HotSpot虚拟机第一款真正意义上的并发收集器,第一次实现了让垃圾收集线程与用户线程基本上同时工作。CMS收集器是一种标记-清除算法实现的,运行过程如下:- 初始标记(CMS Initial Mark): 暂停所有的其它线程,并记录下直接与GC ROOTS相连的对象,速度很快- 并发标记(CMS Concurrent Mark): 同时开启GC和用户线程,用一个闭包结构去记录可达对象,但并不能保证包含单签所有的可达对象;因为用户线程可能会不断地更新引用域,所以GC线程无法保证可达性分析的实时性,会跟踪记录这些发生引用更新的地方。- 重新标记(CMS Remark): 该阶段就是为了修正并发标记期间因为用户线程继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的挺短时间一般会比初始标记阶段的时间稍长,远远比并发标记时间短。- 并发清除 (CMS Concurrent Sweep): 开启用户线程,同时GC线程开始对标记的区域清扫。优点: 并发收集、低停顿缺点: - 对CPU资源敏感- 无法处理浮动垃圾- 使用标记-清除算法会导致空间碎片产生
对齐填充Padding(保证对象是8个字节的整数倍)
同清除算法一样,但后续不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域,既解决了内存碎片问题,也规避了复制算法只能利用一半内存区域的弊端缺点: 对内存变动更频繁,需要整理所有存活对象的引用地址,在效率上比复制算法差很多
Serial(串行)收集器
操作数栈是虚拟机栈中用于进行字节码执行的数据结构。在方法执行过程中,各种字节码指令不断地往操作数栈进行数据的写入和提取,以完成方法的执行。JVM是基于栈的执行引擎,其中所指的栈就是操作数栈.
本地方法库
压栈
类加载的生命周期
Loading 加载
ParNew收集器
垃圾回收算法
实例数据Instance data
类加载器子系统classload(F)
堆内存模型
F 如Student.java
1.线程是用来执行方法的,至于怎么执行,取决于虚拟机栈。2.我们定义的常量和静态变量是存在方法区的,就是用于线程之间共享的。
2,直接访问对象reference直接指向了对象类型数据,那么java堆对象分布中就必须考虑如何放置访问类型数据的相关信息,reference存储的直接就是对象地址。好处就是,减少一次指针定位的时间开销
JIT: 当虚拟机发现某个方法或代码块运行特别频繁时,就会把这些代码认定为\"Hot Spot Code(热点代码)\",为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化,完成这项任务的正是JIT编译器现在主流的商用虚拟机(如:HotSpot、J9)中几乎都同时包含解释器和编译器(JRockit是个例外,它内部没有解释器,因此会有启动相应时间长之类的缺点,但它主要面向服务端的应用,这类应用一般不会重点关注启动时间)。二者各有优势,当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译的时间,立即执行;当程序运行后,随着时间的推移,编译器主键会发挥作用,把越来越多的代码编译成本地代码后,可以获取更高的执行效率。解释执行可以节约内存,而编译执行可以提升效率。热点代码:被多次调用的方法被多次调用的循环体
加载 初始化
判断对象可回收
Student Class
getClass
准备2.2
JVM
1,指针碰撞:依靠连续的内存空间,靠指针的移动来分配内存。2,空间列表:由固定的列表记录内存分配的信息,每一线程指定一块空间。TLAB
Object
根据new的参数在常量池中定位一符号引用
操作压栈
JAVA源码级编译器
标记-整理算法
堆(Heap)
方法区(非堆)Method Area
类似于ParrallelNew收集器,关注点是吞吐量(CPU利用率,就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值),CMS等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。该收集器提供参数供用户找到最合适的停顿时间或最大吞吐量。
加载1
parNew
JAVA源文件
语义分析器
给对象添加一个引用计数器,每当有一个地方引用,计数器就加1.当引用失效,计数器就减1,任何时候计数器为0的对象就是不可能再被使用的。缺点:很难解决对象之间循环引用的问题。例如:除了对象a和b相互引用着对方之外,再无任何引用;但由于它们互相引用对方,导致它们的引用计数器都不为0,于是引用计数器无法通知GC回收它们。
Student2
Parallel
使用4
To(s1)
方法区是一种定义,概念。而所谓永久带或元空间是其一种实现机制
Student.class
0 条评论
回复 删除
下一页