JVM垃圾收集器复习

老年代的担保机制:当一个大对象分配不到young区的时候就会分配到老年代,当young gc后仍有大量对象存活,也需要老年代进行分配担保,把survivor无法容纳的对象直接送入老年代。默认2:1(9:1)

增量回收:无论是标记清除-标记复制、标记整理(随机(双指针)、线性、滑动(Lisp2))算法,都类似于大扫除,增量回收是与运用程序交替回收,三色标记算法为例子。

hotspot每个垃圾收集器都会STW

三色标记:

并发导致的

多标-浮动垃圾

本应该回收,但是没有回收

当成黑色的,下一轮再回收

漏标-读写屏障(保证在并发的过程中,对象的引用更新不会导致某些对象错过标记)

        1、灰色断开白色,灰色引用发生了变化 原始快照,记录下删除引用,再以灰色对象为根,重新扫描 G1

        2、黑色引用上面的同一白色 增量更新,把这个引用记录下来,并发结束后以黑色对象为根重新扫描 CMS

        两个要同时满足,才满足漏标的情况

SERIAL:单核性能高,没有线程上下文切换代价 标记复制

SERIALOLD:标记整理

ParNew:serial多线程版本,标记复制,多线程减小stw时间

parallel scavenge:关注吞吐量

parallel old:吞吐量 标记整理

垃圾回收算法:
  • 标记清除算法
    • 找出需要回收的对象,并且标记
    • 清除被标记的对象,释放内存空间
    • 缺点:大量空间碎片,标记和清除效率都很低
    • 算法:首次适应算法、最佳适应算法、最差适应算法(分配最大的分块)
  • 标记复制算法
    • 将内存划分出两块相等的区域,一块使用完了就拷贝到另外一块,空间利用率比较低
  • 标记整理算法
    • 标记清除的基础上再多了整理
      • 随机整理
        • 与刚开始的排列关系以及引用关系无关
        • 双指针整理算法:先移动位置在更新标记前面预估大小,后面找对象判断大小,留出空间
      • 线性整理
        • 将有关联的对象放在一起
      • 滑动整理
        • 按照原有的顺序进行整理
        • Lisp2:三指针算法,Free留位置,Scan找存活对象,第二次更新对象地址,第三次移动对象,需要额外空间存储
CMS:最短停顿时间,标记清除算法!!!!内存碎片 CMS和paraller old可以一起使用

大量空间碎片,吞吐量低

  • 初始标记:找到所有GCROOT STW,并且找到与之相关联的第一个对象
  • 并发标记:找到引用链上所有节点(并发),此时有个问题,如果老年代的对象被新生代引用了,该怎么办,结合CMS目的是最短停顿时间,那就先进行一次young gc
    • 并发预处理:
    • 可中断的预处理:必须重新扫描新生代,但是新生代不清理对象很多,所以minor gc一下,预处理就是并发前的工作做完,可终止的并发预处理就是等5s进行一次young gc,如果没有发生的话有提供的参数,可以强制进行
  • 重新标记:增量更新,重新对新增的引用深度扫描
  • 并发清理

记忆集:针对跨代引用问题提出的思想,非收集区域指向收集区域的数据结构 卡表是具体实现,字节数组 一字节,标记脏卡什么的,一个卡表对应一个512字节卡页,同时增量更新原始快照也会用到,提高回收效率

Foregroud CMS:

并发搜集器不能在年老代填满之前完成不可达(unreachable)对象的回收 ,或者 老年代中有效的空闲内存空间不能满足某一个内存的分配请求 ,此时应用会被暂停,并在此暂停期间开始垃圾回收,直到回收完成才会恢复应用程序。这种无法并发完成搜集的情况就成为 并发模式失败(concurrent mode failure) ,而且这种情况的发生也意味着我们需要调节并发搜集器的参数了。

简单来说,也就是我去进行并发标记的时候,内存不够了,这个时候我会进入STW,并且开始全局Full GC.

MSC(标记整理)他的回收方式其实就是我们的滑动整理,并且进行整理的时候一般都是两个参数

-XX:+UseCMSCompactAtFullCollection 
-XX:CMSFullGCsBeforeCompaction=0
这两个参数表示多少次FullGC后采用MSC算法压缩堆内存,0表示每次FullGC后都会压缩,同时0也是默认值

G1:垃圾优先

划分为2048个region ,每个1~32M

原文是copy-整理算法--标记整理

分代收集

可预测的停顿,优先回收垃圾最多的Region区域

初始标记 GCRoots

并发标记 可达性分析

最终标记 修正变动数据 原始快照

筛选回收 对回收价值和成本进行排序,根据用户所期望的GC停顿时间指定回收计划

除了并发标记都STW

Tlab本地线程缓冲区:分配空间时,为了提高JVM的运行效率,应当尽量减少临界区范围,避免全局锁。G1的通常的应用场景中,会存在大量的访问器同时执行,为减少锁冲突,JVM引入了TLAB(线程本地分配缓冲区 Thread Local Allocation Buffer)机制。

Rset类似于记忆集

稀疏表:本质上就是一种Hash表,Key是Region的起始地址,Value是一个数组,里面存储的元素是卡页的索引号。

细粒度位图:就是一个C位图,但是这个位图,可以详细的记录我们的内存变化,包括并发标记修改,对应元素标识等 当稀疏表指定region的card数量超过阈值时,则在细粒度位图中创建一个对应的PerRegionTable对象。一个Region地址链表,维护当前Region中所有card对应的一个BitMap集合。

粗粒度位图:当细粒度位图 size超过阈值时,所有region 形成一个 bitMap。如果有region 对当前 Region 有指针指向,就设置其对应的bit 为1,也就是粗粒度位图

CSET

  1. 年轻代区块:在每次垃圾收集循环中,所有的年轻代区块都会被包括在CSet中,因为G1 GC采用的是分代收集策略,必须定期清理年轻代以回收空间。

  2. 选定的老年代区块:除了年轻代区块,CSet还可能包括一些老年代区块。G1 GC会根据各个区块的回收价值(即,预期能够回收的内存量与收集该区块所需时间的比率)和GC停顿时间目标来选择一些老年代区块进行清理。这样做旨在平衡垃圾收集的效率和应用程序的停顿时间。

写屏障:因为Store Buffer导致读写的顺序不一致,而写屏障可以解决这个问题

当CPU执行写操作时,出于性能优化的考虑,写操作不是直接写入主内存,而是首先被写入到该CPU核心的StoreBuffer中。StoreBuffer允许CPU继续执行后续指令而不必等待写操作实际完成。因为重排会有读写不一致!如果一个核心在其Store Buffer中有未刷新到主内存的写操作,而另一个核心尝试读取相同的内存位置,它可能读到旧的数据,从而导致数据不一致。

内存伪共享:

写屏障的内存伪共享问题: 如果不同线程对对象引用的更新操作,恰好位于同一个64B区域内,这将导致同时更新卡表的同一个缓存行,从而造成缓存行的写回、无效化或者同步操作,间接影响程序性能。

不采用无条件的写屏障,而是先检查卡表标记,只有当该卡表项未被标记过才将其标记为dirty。 这就是JDK 7中引入的解决方法,引入了一个新的JVM参数-XX:+UseCondCardMark,

  • 32
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值