[java] 图文示八股
图文示八股
JVM
JVM内存模型
栈和堆区别
栈:
- 线程私有,线程安全
- 每个线程创建时分配独立的栈
- 存储函数方法执行时的栈帧
- 自动管理,与作用域绑定
- 后进先出,无内存碎片问题
堆:
- 线程共享,非线程安全
- JVM启动时创建,整个JVM进程只有一个堆
- 存储对象实例和数组
- 垃圾回收器GC管理
- 可能有内存碎片问题
Java对象结构
- 对象头
- 实例数据,涉及字段重排:基本类型优先 long/doulble > int/float > short/char > boolean/byte > 引用类型;父类字段 > 子类字段
- 对齐填充:对象大小必须是8字节的倍数
判断对象可以被回收
通过 “可达性分析算法” 判断对象是否能关联到根对象;不可达对象进入回收候选队列,若未通过finalize()自救,且无特殊引用保护,则最终会被 GC 回收。
强引用:Java默认,只要存在就不会回收
软引用(SoftReference):内存不足时才会回收,适合缓存;
弱引用(WeakReference):下次 GC 时必然回收,适合临时关联;
虚引用(PhantomReference):仅用于跟踪对象回收过程,无法通过虚引用获取对象。
垃圾回收算法
标记-清除算法
- 标记: 从GC Roots开始,标记所有可以访问的对象
- 清除: 遍历整个堆,释放未被标记的对象
优点: 实现简单
缺点: 内存碎片,遍历整个堆效率低
标记-复制算法
- 将堆内存划分为两个大小相等的区域(如 From 区和 To 区),只使用其中一个区域(From 区);
- 标记: 标记 From 区中所有可达对象
- 复制: 将所有标记对象复制到 To 区,并更新引用
- 清空 From 区,交换 From 和 To 区的角色
优点: 避免内存碎片,效率高
缺点: 内存利用率低:堆内存只能使用一半
标记-整理算法
- 标记: 与 “标记-清除” 相同,标记所有可达对象
- 将所有可达对象向堆内存的一端移动,集中排列,然后直接清理边界外的所有内存(未标记对象)
优点:解决内存碎片,效率比 “标记-复制” 高
缺点:移动对象,比 “标记-清除” 效率低
分代收集算法
核心思想:基于 “对象存活周期不同” 的观察(大部分对象存活时间短,少数对象存活时间长),将堆内存划分为新生代和老年代,针对不同代采用不同算法:
新生代:对象存活率低,用标记-复制算法(高效且无碎片)
老年代:对象存活率高,用标记-清除或标记-整理算法(避免频繁复制的高成本)
几乎所有现代 JVM(如 HotSpot)的默认回收策略(如 CMS、G1、ZGC 等均基于分代思想优化)
