Java垃圾收集器与内存分配策略

时间:2020-07-01 09:45:16   收藏:0   阅读:54

垃圾收集器与内存分配策略

概述

程序计数器,虚拟机栈,本地方法栈随线程创建而产生,随线程销毁而消失,内存的分配和回收具有确定性,一般不考虑回收问题.


对象存活性判断

引用计数算法(Reference Counting)

特点:

可达性分析算法(Reachability Analysis)

特点:

GC Roots对象

引用的分类

分类:

强引用

软引用

示例:

Object obj = new Object();
SoftReference soft = new SoftReference(obj); // 创建一个软引用

obj = null; // 原对象设为null

Object getRef = soft.get(); // 若原对象没有被回收,则通过get()方法获取强引用

ReferenceQueue queue = new ReferenceQueue(); // 引用对象队列
SoftReference newSoft = new SoftReference(obj, queue); // 创建软引用时设置一个引用对象队列,若软引用指向的对象被回收,则引用对象进入队列
newSoft = null;

弱引用

WeakReference<Object> weakRef1 = new WeakReference<>(new Object());
System.out.println(weakRef1.get());
System.gc();
System.out.println(weakRef1.get()); // 只有弱引用,直接回收

Object obj = new Object();
WeakReference<Object> weakRef2 = new WeakReference<>(obj);
System.out.println(weakRef2.get());
System.gc();
System.out.println(weakRef2.get()); // 有强引用,不会被回收

虚引用

ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> ref = new PhantomReference<Object>(new Object(),queue);

不可达与回收


回收方法区

回收的内容:

常量:常量池中的类,接口,方法,字段的符号引用在没有对象引用时可能被清除。

类型:需满足三个条件:


垃圾收集算法

分类:

分代收集理论(Generational Collection)

假说:

对Java堆的分类:(按照对象经历过垃圾收集的次数)

注:

对GC的分类:

标记-清除算法(Mark-Sweep)

过程:

  1. 标记:标记出需要回收的对象。
  2. 清除:统一回收所有被标记的对象。

缺陷:

标记-复制算法

半区复制(Semispace Copying)

缺陷:

Appel式回收

标记-整理算法(Mark-Compact)

缺陷:

注:


HotSpot算法细节实现

根节点枚举


经典垃圾收集器

Young generation:

Tenured generation:

Serial收集器

特点:

ParNew收集器

特点:

注:(收集器中的并行和并发)

Parallel Scavenge收集器

特点:

Serial Old收集器

特点:

Parallel Old收集器

CMS收集器(Concurrent Mark Sweep)

过程:

  1. 初始标记(CMS inital mark)
  2. 并发标记(CMS concurrent mark)
  3. 重新标记(CMS remark)
  4. 并发清除(CMS concurrent sweep)

详细介绍:

缺陷:

参数:
* -XX:CMSInitiatingOccupancyFraction:设置触发垃圾收集的老年代使用率.
* -XX:+UseCMSCompactAtFullCollection:设置每多少次Full GC前进行一次内存碎片合并.(0:每次都进行)

Garbage First收集器(G1)

特点:

G1实现可预测的停顿时间的原因:

实现细节:

回收过程:

  1. 初始标记(Initial Marking)
    • 标记GC Roots直接关联的对象.
    • 修改TAMS指针,使得与用户线程并发运行时可以在Region分配新对象.
    • 停顿线程,耗时短,使用Minor GC完成.
  2. 并发标记(Concurrent Marking)
    • 从GC Roots开始对堆中对象进行可达性分析.
    • 扫描整个堆中的对象图,找到要回收的对象.
    • 耗时长,可与用户线程并发执行.
    • 扫描后更新SATB记录并发时有引用变动的对象.
  3. 最终标记(Final Marking)
    • 暂停用户线程,处理并发阶段结束后存在的少量SATB记录.
  4. 筛选回收(Live Data Counting and Evacuation)
    • 更新Region统计信息.
    • 对每个Region回收价值和成本进行排序.
    • 根据用户期望停顿时间指定回收计划.
    • 选择Region组成回收集.
    • 将回收集中存活对象复制到空Region中,清理旧的Region.
    • 需暂停用户线程,由多条收集器线程并行完成.

注:

G1与CMS的对比


低延迟垃圾收集器

衡量垃圾收集器的三个指标:

各种收集器的并发情况:

收集器 Young GC Old GC
Serial,Parallel Copy(非并发) Mark == >Compact(非并发)
CMS Copy(非并发) Init Mark(非并发) == >Concurrent Mark(并发) == >Finish Mark(非并发) == >Concurrent Sweep(并发)
G1 Copy(非并发) Init Mark(非并发) == >Courrent Mark(并发) == >Compact(并发)
Shenandoah,ZGC Init Mark(非并发) == > Concurrent Partial(并发) == > Finish Mark(非并发) Init Mark(并发) ==> Concurrent Mark(并发) ==> Finish Mark(非并发) == > Concurrent Compact(并发)

Shenandoah收集器

工作流程:

三个主要阶段:

  1. 并发标记
  2. 并发回收
  3. 并发引用更新

对象移动和用户程序并发问题

  1. 传统方式:原来内存上设置保护陷阱(Memory Protection Trap),用户程序访问旧内存地址会产生自陷中断,进入核心态,由其中的代码逻辑将访问转发发哦复制后的新对象中。(用户态与核心态切换,成本大)
  2. 转发指针(Forwarding Pointer/Indirection Pointer):每个对象前有一个引用字段,若正常,则指向自己;若处于并发移动,则指向新对象。(增加额外内存消耗和转向开销)
    并发更新问题:对象移动时,保证对象的更新发生在新对象上。 == >通过CAS操作保证用户线程和收集器线程对转发指针的访问只有一个会成功。
    为了实现Brooks Pointer,使用读屏障。读取的频率高,不能使用重量级操作。 ==> 使用基于引用访问屏障(Load Reference Barrier)。只拦截对象中数据类型为引用类型的读写操作。

技术图片

ZGC收集器

ZGC收集器是一款基于Region内存布局的,不设分代的,使用了读屏障,染色指针和内存多重映射等技术实现可并发的标记-整理算法的,以低延迟为首要目标的垃圾收集器.

ZGC的内存布局

名称 容量 特点
小型Region 2MB 放置小于256KB的小对象
中型Region 32MB 放置大于等于256KB小于4MB的对象
大型Region 动态变化,为2MB的整数倍 放置4MB以上大对象,每个Region只放一个对象,不会被重分配

并发整理算法

染色指针的实现

使用多重映射(Multi-Mapping):将多个不同的虚拟内存地址映射到同一个物理内存地址上.
可以将不同的地址段映射到同一个物理内存空间.

ZGC运行过程(都是并发执行的)

优势:

缺陷:

参考:

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!