1. JVM整体结构
学习JVM的目的:性能调优
1.1. 字节码文件
源代码通过编译器生成.class字节码文件
1.2. 类加载器
1.2.1 加载 Loading
类加载器包括:引导类加载器(BootStrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用类加载器(Application ClassLoader)
1.引导类加载器(BootStrap ClassLoader启动类加载器):用来加载Java的核心库
/jre/lib/jar包、resource.jar包。负责扩展类加载器和应用类加载器,并指定为
他们的父类加载器。
2.扩展类加载器:java编写,间接派生于ClassLoader类,父类加载器为启动类加载
器。从在JDK的安装目录jre/lib/ext子目录(扩展目录)下加载类库。用户创建的jar
放在此目录下,也会自动由扩展类加载器加载。
3.应用程序类加载器:该类加载是程序中默认的类加载器,一般来说,java应用的类
都是由它完成加载的。
4.自定义加载器:通过继承抽象类Java.lang.ClassLoader类的方式,实现自己的类
加载器,以满足一些特殊的需求。
1.2.2 链接 Linking
Linking 包含三个环节:验证Verify、准备Prepare、解析Reslove
1.2.3 初始化 Initialization
静态变量的初始化
1.3. 运行时数据区 Runtime Data Area
1.3.1 程序计数器
程序计数器:存储指向下一条指令的地址。
程序计数器不存在GC 和 OOM.
除了程序计数器外,其他几个运行时区域的都有可能发生OutOfMemmoryError
1.3.2 虚拟机栈
- 虚拟机栈存储着以下内容:栈帧(局部变量表、动态链接、方法返回地址)
- 虚拟机栈描述的是Java方法执行的线程内存模型。
1.3.3 本地方法栈
本地方法栈:是为虚拟机使用的本地方法服务。
本地方法栈和虚拟机栈发挥的作用相似的,虚拟机栈为虚拟机执行java方法服务,
而本地方法则是为了虚拟机使用到的本地方法服务。
1.3.4 堆
创建Java对象,存放对象实例。
1.3.5 方法区(Method Area)
方法区:存放被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。 注:字符串常量池则存在于方法区。
1.4. 执行引擎
执行引擎:将运行时数据区的指令翻译成机器指令,供CPU执行。
1.4.1 解释器
1.4.2 即时编译器
1.4.3 垃圾回收器
问题:如果自己写一个Java虚拟机的话,主要考虑哪些结构?
答:类加载器和执行引擎
2. 类加载器子系统
2.1类加载器子系统的作用
2.2 类的加载过程
2.3 类的链接过程
2.4 类的初始化
初始化阶段:执行类构造器方法()的过程。
3.双亲委派机制(类加载器涉及双亲委派机制)
3.1 双亲委派机制工作原理
- 案例:自定义了一个String类,String str = new String(); 默认调用自定义的String. 蕴含着双亲委派机制。
- 双亲委派机制工作原理:
3.2 双亲委派机制优势
- 避免类的重复加载
- 保护程序安全,防止核心API被随意篡改。(自定义类:java.lang.String)
3.3 沙箱安全机制
4. 运行时数据区(堆:Heap Area)
4.1 堆的核心概述
- 描述该图
- 所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer)TLAB。
- java堆的描述:所有的对象实例以及数组都应该在运行时分配在堆上。
- 数组和对象永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象和数组在堆中的位置。
- 在方法结束后,堆中的对象不会立马移除,仅仅在垃圾收集的时候才会被移除。
- 堆是GC执行垃圾回收的重点区域。
4.2 堆的内存细分
大厂面试jdk8中内存有哪些变化? 堆空间的元空间
4.3 设置堆内存大小与OOM
1.设置堆空间大小的参数 -xms 用来设置堆空间(年轻代和老年代)的初始内存大小 -xmx 最大内存大小
4.4 年轻代与老年代
- 年轻代含:伊甸园Eden、Survivor 0(幸存者0区 From)、Survivor 1(To).
- 参数设置
-XX: NewRatio 设置新生代与老年代的比例,默认值是2. - YGC / Minor GC
1. 当伊甸园区满时会触发 Minor GC
2. 年龄计数器age 达到上限阈值,需要晋升到老年代 (默认age = 15)
3. s0 : s1 = 1:1
4. 关于垃圾回收:频繁在新生区收集,很少在养老区收集,几乎不在永久区/元空间收集。
YGC触发时,幸存者会被动进行垃圾回收。 4. FGC / Full GC 老年区满时(或者存放大文件)触发FGC.
4.5 Minor GC、Major GC与Full GC区别
4.6 Full GC 触发机制
触发 Full GC执行的情况有5种:
5. 执行引擎
- 执行引擎的概述(视频110)
- 执行引擎的工作流程
- Java代码编译和执行的过程
6. 垃圾回收算法 GC
6.1 什么是垃圾?
垃圾是指在运行程序中没有任何指针指向的对象。
6.2 为什么需要GC?
1 内存迟早会被消耗完、2 JVM将整理出的内存分配给新的对象(案例 买1w的苹果)、3 应用程序业务庞大,没有GC就不能保证应用程序的正常进行。
6.3 垃圾回收机制
- 内存泄漏:内存区由于程序员编码的问题忘记了被回收,导致内存泄漏, 长时间积累—>OOM.
- Java中自动内存管理。
- GC的作用区域:方法区(元空间)和堆。 程序计数器、java栈、本地方法栈 不存在GC. 程序计数器也不存在溢出OOM.
6.4 垃圾回收相关算法
6.4.1 标记阶段:引用计数算法、可达性分析算法
垃圾标记阶段:对象存活判断-----》对象存活的两种方式:上述的引用计数和可达性分析算法。
6.4.1.1. 引用计数算法
1 定义:对于每个对象保存一个整形的引用计数器属性,用于记录对象被引用的情况。 2 优点:实现简单,判断效率高、回收没有延时性。 3 缺点:存储空间的开销、时间开销 、 无法处理循环引用。 4 循环引用的案例:
6.4.1.2. 可达性分析算法
1 基本思想:
2 哪些对象可以作为GC Roots的对象: 1 虚拟机栈中引用的对象 2 方法区中的类静态属性引用的对象 3 方法区中常量引用的对象 4 本地方法栈JNI(Native方法)引用的对象
6.4.2 清除阶段:标记-清除算法、复制算法、标记-压缩算法
6.4.2.1 标记-清除算法(Mark-Sweep算法)
1 原理 2 案例 3 标记-清除算法的缺点 ①2次遍历—>效率不算高; ②在进行GC的时候,需要停止整个应用程序,导致用户体验差; ③这种方式清理出来的·空闲空间内存是不连续的,产生内存碎片。需要维护一个空闲列表。
6.4.2.2 复制算法 (新生代S0和S1区)
1 原理 2 案例 3 复制算法的优缺点 注意适用场景:(存活对象少、垃圾对象多的情况下)大部分对象死亡,少量对象存活 复制到B区,----》新生代区 S0与S1区非常合适。
6.4.2.3 标记-压缩算法(Mark-Compact)
1 背景 :改进于标记-清除法。 2 原理 标记-压缩算法的最终效果等同于标记–清除算法执行后,再进行一次内存碎片整理。 3 优缺点
6.5 对比三种算法
7. 垃圾回收器(待更新…)
7.0 垃圾回收器的分类:
1 按线程数分可以分为串行垃圾回收器和并行垃圾回收器。 适用场景:串行垃圾回收器—单CPU. 案例: 2 按工作模式分可以分并发式垃圾回收器和独占式垃圾回收器 案例: 3 碎片处理方式分可以压缩式和非压缩式垃圾回收器 4 按工作的内存空间分可以分为年轻代和老年代垃圾回收器 评估GC的性能指标:
7.1 Serial收集器(单线程、 复制算法):
新生代单线程收集器,标记和清理都是单线程,优点是简单高效;
7.2 ParNew收集器 (Serial+多线程):
新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;
7.3 Parallel Scavenge收集器 (多线程复制算法、高效):
新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;
7.4 Serial Old收集器 (单线程标记整理算法):
老年代单线程收集器,Serial收集器的老年代版本;
7.5 Parallel Old收集器 (多线程标记整理算法):
老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;
7.6 CMS(Concurrent Mark Sweep)收集器(多线程标记清除算法):
老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。
7.7 G1(Garbage First)收集器 (标记-整理算法):
Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。
|