JVM
2023-03-15 12:42:09 0 举报
AI智能生成
jvm
作者其他创作
大纲/内容
JVM下篇:性能监控与调优
JVM上篇:内存与垃圾回收
JVM与Java结构体系
整体结构
详细结构
类加载子系统
加载
目的
类加载器
引导类加载器(Bootstrap ClassLoader)
自定义类加载器(User-Defined ClassLoader)
扩展类加载器(Extension ClassLoader)
系统类加载器(系统类加载器,AppClassLoader)
用户自定义类加载器
优势
沙箱安全机制
其他:判断两个class对象是否相同?
链接
验证
准备
解析
初始化
运行时数据区
运行时数据区及概述
整体结构
线程
系统线程主要类别
扩展:JVM优化方向
程序计数器(PC计数器也称为程序钩子)
介绍
作用
举例说明
问题
虚拟机栈
虚拟机栈概述
可能出现的异常
设置栈内存大小
栈的储存单位
栈帧
运行原理
内部结构
局部表量表(Local Variables)
结构
slot的理解
slot重复利用
静态变量与局部变量的对比
补充
操作数栈(Operand Stack)
结构
作用
关键点
代码试例
栈顶缓存技术(Top Of Stack Cashing)技术
动态链接(Dynamic Linking)
结构
概念
为什么需要运行时常量池呢?
方法的调用:解析与分配
方法的绑定机制
静态链接
动态链接
早期绑定
晚期绑定
虚方法和非虚方法
概念
指令
关于invokednamic指令
动态类型语言和静态类型语言
方法重写的本质
方法的调用:虚方法表
方法返回地址(return address)
内容
方法的结束方式
个人理解
一些附加信息
栈的相关面试题
举例栈溢出的情况?(StackOverflowError)
调整栈大小,就能保证不出现溢出么?
分配的栈内存越大越好么?
垃圾回收是否涉及到虚拟机栈?
各区域情况
方法中定义的局部变量是否线程安全?
本地方法接口
定义
为什么使用Native Method?
本地方法栈
定义
堆
堆(Heap)的核心概述
堆内存细分
内部结构
JDK1.7
JDK8之前和8
设置堆内存大小与OOM
堆空间大小的设置
OutOfMemory举例
年轻代与老年代
分类
结构
设置参数
-XX:NewRatio
-xx:SurvivorRatio
-XX:-UseAdaptivesizePolicy
-Xmn
图解对象分配过程
过程
过程图解
流程图
总结
常用调优工具
Minor GC,Major GC、Full GC
Minor GC
Major GC
Full GC
堆空间分代思想
内存分配策略
原则
为对象分配内存:TLAB
为什么有TLAB(Thread Local Allocation Buffer)?
什么是TLAB?
图解
TLAB的再说明
对象分配内存分配图解
小结:堆空间的参数设置
官网
常用参数
堆是分配对象的唯一选择么?
逃逸分析
逃逸分析:代码优化
栈上分配
举例
同步省略
举例
分离对象或标量替换
举例
逃逸分析小结
本章小结
方法区
栈、堆、方法区的交互关系
结构
方法区的理解
在哪里?
方法区的基本理解
HotSpot中方法区的演进
设置方法区大小与OOM
设置方法区内存的大小
JDK7及以前
JDK8及以后
举例
如何解决这些OOM
方法区的内部结构
方法区(Method Area)存储什么?
经典结构图
方法区的内部结构
类型信息
域(Field)信息
方法(Method)信息
non-final的类变量
举例
补充说明:全局常量(static final)
运行时常量池 VS 常量池
为什么需要常量池?
常量池中有什么?
小结
运行时常量池
方法区使用举例
方法区的演进细节
变化
变化图示
JDK1.6
JDK1.7
JDK1.8
为什么永久代要被元空间替代?
StringTable为什么要调整位置?
静态变量存放在那里?
代码
结论
方法区的垃圾回收
回收内容
字面量
符号引用
回收机制
字面量
符号引用
本章小结
整体结构
面试题
对象实例化以及直接内存
对象的实例化
创建对象的方式
new
最常见的方式
变形1:x的静态方法(单例)
变形2:xBuilder/xFactory的静态方法(建造者、工厂模式)
Class的newInstance():放射的方式,只能调用空参的构造器,权限是public,已过时
Constructor的newInstance(x):反射的方式,可以调用空参和有参的构造器,无权限要求
使用clone():不调用任何构造器,当前类需要实现cloneable接口,实现clone()方法,实际是从写Object类的clone()
使用序列化:从文件、网络中获取对象发二进制流
使用第三方库Objensis
创建对象的步骤
1. 判断对象对应的类是否加载、链接、初始化
2. 为对象分配内存
如果内存规整
指针碰撞
如果内存不规整
维护空闲列表
说明
3. 处理并发问题
采用CAS失败重试、区域加锁保证更新的原子性
每个线程预先分配一块TLAB:通过设置 -XX:+UseTLAB参数来设定
4. 初始化分配到的内存
所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用
5. 设置对象的对象头
6. 执行init方法进行初始化
简述
1. 加载类元信息
2. 为对象分配内存
3. 处理并发问题
4. 属性的默认初始化(零值初始化)
5. 设置对象头信息
6. 属性的显示初始化、代码块中初始化、构造器中初始化
说明:给对象属性赋值的操作(4类)
属性的默认初始化
显式初始化
代码块中初始化
构造器中初始化
对象的内存布局
对象头(Header)
包含两部分
运行时元数据
哈希值(HashCode)
GC分代年龄
锁状态标志
线程持有的锁
偏向线程ID
偏向时间戳
类型指针
指向类元数据InstanceKlass,确定该对象所属的类型。
说明:如果是数组,还需记录数组的长度
实例数据(Instance Data)
规则
相同宽度的字段总是被分配在一起
父类中定义的变量会出现在子类之前
如果CompactFields参数为true(默认为true):子类的窄变量可能插入到父类变量的空隙
说明:它是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(包括从父类继承下来的和本身拥有的字段)
对齐填充(Padding)
说明:不是必须的,也没有特别的含义,仅仅起到占位符的作用
举例
代码
图示
对象的访问定位
图示
创建对象的目的是为了使用它
JVM是如何通过栈帧中的对象引用访问到其内部的对象实例的呢?
定位,通过栈上reference访问
对象访问方式主要有两种
句柄访问
图示
实现
好处
直接指针(Hotspot采用)
图示
实现
好处
直接内存
直接内存概述
非直接缓存区
图示
直接缓存区
图示
说明
StringTable
String的基本特性
String Pool
String的内存分配
StringTable为什么要调整?
String的基本操作
字符串拼接操作
总结
常量与常量的拼接结果在常量池,原理是编译期优化
常量池中不会存在相同内容的变量
只要其中有一个是变量,结果就在堆中。变量拼接的原理是StringBuilder
如果拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址
字符串拼接操作性能对比
intern()的使用
StringTable的垃圾回收
G1中的String去重操作
执行引擎
执行引擎概述
结构
图示
作用
执行引擎的工作流程
概述
图示
Java代码编译和执行过程
总体流程
编译成字节码(前端编译器)
执行字节码(后端编译器)
解释器
JIT编译器
为什么Java是半编译半解释型语言?
概述
图示
机器码、指令、汇编语言
机器码
指令
指令集
汇编语言
高级语言
C、C++源程序执行过程
字节码
解释器
工作机制
分类
JIT编译器
Java代码的执行分类
HotSpot JVM执行方式
概念解释
热点代码及探测技术
方法调用计数器
运行图示
概念
设置方式
热点衰减
概念
设置方式
回边计数器
运行图示
概念
HotSpotVM 可以设置程序执行方法
HotSpotVM中 JIT 分类
分类
使用规则
C1和C2优化方向
总结
Graal编译器
AOT编译器
垃圾回收
垃圾回收概述
垃圾回收相关算法
垃圾回收相关概念
垃圾回收器
JVM中篇:字节码与类加载
0 条评论
下一页