自动内存管理
- 运行时数据区域
- 程序计数器
- Java虚拟机栈
- Java方法执行的线程内存模型
- 每个方法在Java方法中的体现是栈帧
- 本地方法栈
- 栈帧内专门为本地方法服务
- Java堆
- 被所有线程共享
- 唯一目的是存放对象
- 垃圾收集器管理的内存区域(所以也有人称之为”GC“堆)
- 堆内实际有线程私有的对象缓存区,来提升线程获取对象的效率
- 方法区/元空间
- 与方法本身的关系并不大,而更多的是存储的常量、静态变量、类型信息等。
- 运行时常量池
- 直接内存
- HotSpot虚拟机与堆中对象分配、布局、访问
- 对象分配
- 可用空间的划分
- 规整的情况下:平移指针
- 不规整的情况下:空闲列表
- 并发冲突
- 缓冲+同步锁/CAS
- 内存初始化
- 分配完内存后,进行内存初始化(赋零值)
- 保证了成员变量默认情况下适用就是零值
- 分配完内存后,进行内存初始化(赋零值)
- 构造函数初始化
- 可用空间的划分
- 对象内存布局
- 对象头、实例数据、空白对齐的padding
- 对象的访问
- 通过栈上的reference访问
- 通过句柄来访问
- reference->句柄->地址
- 通过指针来访问(HotSpot采用)
- reference->地址
- 通过句柄来访问
- 通过栈上的reference访问
- 对象分配
垃圾收集器与内存分配策略
-
对象是否”死亡“
- 引用计数法(不采用)
- 无法解决循环引用的问题
- 可达性分析(采用)
- 判断从GC Root是否可达该结点
- 可以用作GC Root的点
- 虚拟机、本地方法栈中引用的对象
- 静态属性引用的对象
- 类属性中,常量引用的对象
- 引用计数法(不采用)
-
引用的分级
- 只用”被引用“和”未被引用“无法充分描述对象的引用状况
- 比如对于这种场景:当内存空间还足够时,能保留在内存之中,如果内存空间在进行垃圾收集后仍然非常紧张,就扔掉它(缓存)
- 强引用
- 指在程序代码之中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用关系
- 软引用
- 有用,但非必须的对象
- 只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常
- SoftReference
- 弱引用
- 被弱引用关联的对象只能生存到下一次垃圾收集发生为止
- WeakReference
- 虚引用
- 没啥用,起到通知作用
- 只用”被引用“和”未被引用“无法充分描述对象的引用状况
-
垃圾收集算法
- 分代收集理论
- 弱分代假说:绝大多数对象都是朝生夕灭
- 强分代假说:熬过越多次垃圾收集的对象越难消亡
- 跨代假说:跨代引用仅占少数
- 收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储
- 标记清除算法
- 主要问题
- 容易缠身过多的空间碎片
- 主要问题
- 标记复制算法
- 内存分两办,用一半,剩下的一半在每次垃圾收集的时候,存放活着的对象,原来的一半被清空
- 主要问题
- 如果存活对象过多,那么复制开销大
- 标记-整理算法
- 标记清除+移动
- 分代收集理论
-
HotSpot的算法细节实现
- 略
-
经典垃圾收集器
-
Serial收集器
-
G1
-
ZGC
-