Xmind Zen 挺好用的
学习了《深入理解Java虚拟机》–周志明之后的一点点个人总结,如有错误还请指正。
文字版如下
运行时内存
线程私有
虚拟机栈
描述
java方法执行的内存模型
- 存储局部变量表、操作数栈、动态链接、方法出口等信息
方法开始执行时,创建栈帧
- 从方法执行到执行完成对应(一个栈帧)入栈出栈的过程
功能
局部变量表
- 存放该方法调用者所传入的参数,及在该方法的方法体中创建的局部变量。
对象引用(reference类型)
- 可能是指向对象起始地址的引用指针
- 也可能是指向一个代表对象的句柄
returnAddress类型
- 指向一条字节码指令的地址
多线程
- 生命周期与线程一致
抛出异常
线程请求深度大于虚拟机栈允许最大深度时
- StackOverflowError
虚拟机栈可以动态扩展,无法申请到足够内存
- OutOfMemoryError
本地方法栈
描述
与虚拟机栈十分相似
- 只不过针对Native方法服务
功能
多线程
- 生命周期与线程一致
抛出异常
- 同虚拟机栈异常
程序计数器
描述
- 当前线程所执行字节码的行号指示器
功能
- 字节码解释器改变计数器的值
- 如果执行的是native方法,则计数器值为空
多线程
- 每个线程的计数器互不影响,相互独立
jvm多线程的理解
- jvm通过轮流分配处理器执行时间,实现多线程
共享区域
java堆
描述
- 虚拟机启动时创建
功能
存放对象的实例
- jit编译器与逃逸分析技术的发展,栈上分配、标量替换使这一条不那么绝对
存放数组
为了更好的分配和回收会进行细分、功能不变
- 新生代和老年代
- Eden空间、From Survivor空间、To Survivor空间
线程私有的分配缓冲区
- TLAB
GC
- 内存回收的主要区域
抛出异常
堆中没有内存可以完成实力分配并且没法扩展时
- OutOfMemoryError
参数
- -Xmx
- -Xms
方法区
主区域
描述
- 堆的逻辑区域
功能
存储已被虚拟机加载的类信息
- 类的版本、字段、方法、接口等描述信息
- 常量池
常量
- 静态变量
- 即时编辑器编译后的代码
特点
- 不需要连续的内存空间
- 可固定可扩展
- 可以不实现垃圾回收(垃圾回收在此区相对较少)
参数
- 有些虚拟机把分代收集扩展到方法区称为永久代
永久代大小
- -XX:MaxPermSize
运行时常量池
描述
- 用于存放编译期生成的各种字面变量和符号引用
功能
- 还可以保存翻译出来的直接引用
特点
相对于Class文件常量池具备动态性
运行期间也可以讲新的常量放入池中
- String.intern()
抛出异常
方法区无法满足内存分配需求时
- OutOfMemoryError
直接内存
描述
- NIO类可以操作Native函数库直接分配堆外内存
- 通过存储在堆中的DirectByteBuffer对象作为这块内存引用操作
抛出异常
- OutOfMemoryError
参数
主动设置
- -XX:maxDirectMemorySize
默认
- -Xms
对象
对象的创建
类加载
先通过New指令的参数去常量池中定位到一个类的符号引用
- 编译时并不知道一个类的直接内存地址,只能使用(符号)来标识类的地址
如果没有,执行相应的类加载过程
分配内存空间
- 类加载完成后所需的大小可以完全确定
- 将所需的内存区域从Java堆中划分出来
内存分配方式
- 规整的内存(已用和未用有一个区分界限)
零散的区域
- 需要一个空闲列表来统计空闲区域
内存分配时并发性问题
描述
- 正在给A对象分配,指针还没来得及移动,要开始分配B对象,使用了A对象内存区域
解决方案
动作原子性控制
- CAS配上失败重试
作用域控制
- 为每个线程在堆中分配TLAB,每个线程在自己的区域中划分内存
- 如果原来的缓冲区域用完了,需要新的缓冲区来划分内存,则需要同步锁来保证完整性
启用TLAB
- -XX:+/-UseTLAB
翻台
将分配的内存区域置零
- 不包括对象头
- 如果使用TLAB,这一步在TLAB分配时完成
设置
根据对象头
- 对象是那个类的实例
- 如何才能找到类的元数据信息
- 对象的哈希码
- 对象的GC分代年龄等
至此一个对象创建完成,但是对于Java程序来讲对象的创建才刚刚开始,接下来执行init方法
对象的内存布局
对象头包含两部分信息
运行时数据、信息
位数固定
- 如果储存的信息太多时会复用位数空间
类型指针
- 即指向它类元数据的指针
- 虚拟机通过这个指针来确定对象是哪个类的实例
真正储存的有效信息
各类型字段(包括父类)
存储顺序
虚拟机分配策略参数
- 相同宽度的字段总是被分配到一起
- 父类定义的变量会在子类之前
字段在Java源码中的定义顺序
对齐填充
- 保证地址空间时8字节的整数倍
对象的访问定位
通过栈上的reference数据来操作对象
- 指向对象的引用
访问方式
句柄
- Java堆中划分出一块句柄池
- reference存储句柄地址
- 句柄包含对象实例数据与类型数据各自的具体信息
直接指针
- Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息
优缺点
- 直接指针访问速度快,对象移动时需要改变栈中reference
- 句柄每次访问查一遍句柄池,但是对象移动(垃圾收集时)不需要修改栈中reference