jvm学习笔记4----垃圾回收机制与垃圾回收算法

垃圾回收机制与垃圾回收算法-0723

回顾

1.创建对象的过程,重点在于分配内存,两者方式,以及解决并发安全

2.cas加本地内存缓存解决并发安全

3.对象有对象头,设置对象指针,数组必须有记录长度的数据

4.对象头有哈希码、gc、锁标识、线程持有的锁、偏向线程id,偏向时间戳

5.对象的访问,句柄来存,就是中间多了一个指针,hotspot是直接指针,堆里面的指针直接指向数据

6.方法的执行就是栈帧的执行,数据不可能拿到栈中,太大了,所以都是用引用

7.垃圾回收之前必须要判断对象是否在存活,引用计数法无法解决循环引用的问题。

8.gc roots常见的根包括常量、线程栈变量、常量池、JNI(指针),可达叫不可回收,不可达叫可回收

9.finalize(拯救),方法优先级很低,方法不常用,忘记掉!

10.class的回收时非常严格的,需要四到五个条件,

11.各种引用,reference,强引用,不会被回收

12.对象的分配原则,

1 垃圾回收基础知识

主要是回收堆

  • minor gc/young gc
  • major gc(不同地方不一样,需要根据出处的上下文理解)/old gc(更好的说法,cms)
  • full gc(不仅是新生代、老年代、还要加上方法区(1.7之前是永久代,后面是元空间))

2 分代回收理论

  • 大部分对象都是朝生夕死 — 新生代(98%)
  • 熬过多次垃圾回收的就越难回收 — 老年代

3 垃圾回收算法

  • 复制算法 – 新生
  • 标记清除算法、标记整理算法 – 老年

3.1 复制算法

步骤一:先把一般的空间预留,当一般的空间塞满以后,这时就会触发垃圾回收,扫描存活的对象,将存活的copy过去,直接将扫描完的一般格式化(效率高);

步骤二:重复步骤一

步骤一完成后,两个区的身份交换,预留的变成对象分配区域,对象分配区域变成预留

  • 特点
    • 实现简单、运行高效
    • 没有内存碎片
    • 利用率只有一半(缺点)
      • eden区提高效率,标准的eden:from:to = 8:1:1
  • eden区的来源
    • appel式回收
      • 1.eden区满了,将存活的对象复制到from区
      • 2.eden区满了,将存活的对象复制到to区,同时将from区依然存活的复制到to区
      • 3.效率由50提高到90,
      • 4.如果单次回收超过10%会进入老年代
    • 提高空间利用率和空间分配担保
  • 总结
    • 用在新生代

3.2 标记清除算法(mark-sweep)

  • 根据可达性分析做标记
  • 将可回收的进行标记,
  • 特点
    • 位置不连续,产生碎片
      • 对象的分配是一个直接指针,不能分成两段,所以需要对象是连续的,这就要求时连续内存空间
    • 效率略低(两次)
    • 两遍扫描(还要涉及对象的删除)
    • 利用率100%

3.3 标记整理算法

  • 跟标记清除相似,需要整理内存空间
  • 特点
    • 没有内存碎片
    • 效率偏低
    • 两遍扫描、引用指针需要调整(对象保存的地址发生了变换)

4 jvm常用的垃圾回收器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fcuy3mQO-1598880659203)(C:\Users\liusiping\AppData\Roaming\Typora\typora-user-images\image-20200830164616458.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddJguNNo-1598880659205)(C:\Users\liusiping\AppData\Roaming\Typora\typora-user-images\image-20200830164850376.png)]

4.1 单线程垃圾回收器

  • Serial
  • SerialOld

需要暂停所有的用户线程,起一个垃圾回收线程

参数

  • useSerialGC(鸡肋),只能回收几十兆、几百兆的东西

4.2 多线程垃圾回收器

  • Parallel Scavange(默认)
  • Paralledl Old (默认)
  • ParNew(单独针对cms的)

参数

  • UseParallelGC

  • -XX:MaxGCPauseMillis (没什么鸟用)实际的暂停时间可能还变长了

    • 500ms 每隔100s
    • 100ms 每隔10s
  • UseAdaptiveSizePolicy

    • 自适应生成大小,为了提高吞吐量
  • 适用于几百兆到几个g都适用

4.3 stop the world(停顿时间)

如果超过10s,用户体验极其不好,应该不仅仅是为了提高吞吐量

4.4 并发垃圾回收器-cmd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3tWtCqm4-1598880659206)(C:\Users\liusiping\AppData\Roaming\Typora\typora-user-images\image-20200830171355962.png)]

  • 步骤
    • 1.初始标记
      • 可达性分析(直接的gc roots),同时暂停所有用户线程,暂停时间短,所以可以暂停
    • 2.并发标记(让中间标记最长的一段时间并发标记,可以减少stop the wordl的时间)
      • 对gc roots下面的元素进行标记,标记的深度很深,数量级很大,所以时间比较长,因此是并发的和用户线程跑
      • 这必然会产生
    • 3.重新标记
      • 重新标记用户线程新产生的垃圾,此时也需要暂停所有用户线程,但是新产生的垃圾少,所以也能很快标记完
    • 4.并发清除
      • 用户和gc并发执行,时间也比较长
      • 最后重置线程
  • cms中的问题
    • cpu敏感,4核以下,用户很有很强的卡顿感
    • 浮动垃圾,最后一步并发清除的过程中又会产生浮动垃圾
      • 之前是存到68就触发垃圾回收
      • jdk提高到老年代的空间利用率超过92就会触发cms
      • 触发垃圾回收相比parallel要提前
      • 如果超过了能处理的浮动垃圾
        • 此时会用serialOld来取代
    • 内存碎片
      • 大对象分配非常麻烦
      • UseCMSCompactAtFullCollection
    • 问题非常多,浮动垃圾和内存碎片导致垃圾回收器随时可能被一个单线程的serialold代替,所以以前老版本经常重启,每天晚上进行重启,来清除浮动垃圾和内存碎片,所以1.6、1.7、1.8都没有将cms设置为默认垃圾回收期
  • 为什么是标记清除不是标记整理?
    • 因为清除是并发清除,和用户线程并发进行的,可以确保最好并发清除的效率,减少stop the world的时间。

4.5 并发垃圾回收器-g1(garbage first)

设计思想
  • 总是跳不出stop the world的问题,所以想着去预测stw、从而实现控制。

  • 将整个堆空间划成一个整体,切割成一个个的region,从1m~32m,规定是2的次幂大小,

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yJ6kpWGt-1598880659208)(C:\Users\liusiping\AppData\Roaming\Typora\typora-user-images\image-20200830172444689.png)]

  • g1逻辑上也是分代的,

  • 针对大对象,多了一个Humongous,如果对象大于等于512k,判定为大对象,会放到H区,如果更大,就会放到连续的多个H区

  • eden、survivor用复制,old用标记清除/标记整理、humyong等同于老年代

garbage first

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GmSqB5Bu-1598880659209)(C:\Users\liusiping\AppData\Roaming\Typora\typora-user-images\image-20200830173352644.png)]

  • 追求停顿时间(想办法达到?选出其中最有价值的去达到)

  • region区

  • 筛选回收

    • MaxGcPauseMillis 垃圾回收最大暂定时间,是一个软目标,会尽最大努力去实现,不同于parallel强制去做处理
    • 因为划分了区域,不会对整个空间进行垃圾回收,会去选垃圾回收效率比较高的区域进行垃圾回收,这也就是名字的来源。
  • 可预测停顿

  • 算法—复制和标记整理

步骤
  • 初始标记,gc roots,与cms相同,stop the world
  • 并发标记,
    • 解决回收过程中新分配的对象(不是垃圾),TAMS(top at mark start),每一个region,放一个指针(新new出来的存活的对象)
    • 并发标记也会出现漏标问题,SATB(snapshot at the beginning),保存一个快照(内存引用关系)
  • 最终标记,处理漏标对象,stop the world
  • 筛选回收,不会回收整个堆,通过标记已经算出来,每块区域有多少垃圾,哪个回报率最高,stop the world时间最短,可以获得最大的收益,同时会用到标记整理,
    • 相比于cms,是筛选的,
问题
  • 解决了cms里面的痛点,大对象,内存碎片
  • 但是如果region里的对象与另一个region里的对象有依赖怎么办?

5 cms与g1应该怎么选

5.1 选择

  • serial serialold 几十兆到几百兆
  • parallel parallel old 几百兆到几个g
  • cms 几个g到几十个g (对g1起到铺垫作用,jdk1.8与g1有竞争之力,到jdk1.9可能就不如g1了)
  • g1 十几个g到一百多个g(jdk官方文档当堆的空间大于6gb以上或更大,推荐采用g1)
  • cms和g1有重合之处,此时可以参考jdk文档

5.2 并不是cms一定比g1差?

每块region都需要一块区域去解决并发标记所需的内存需要,所以花费的内存空间不一定低(漏标、new出来的对象),但是还是应该选择g1,因为不会有那么多烦恼

回顾

1.只有cms是标记清除,其余基本是标记整理

2.避免full gc,相当耗时间

3.g1因为对区域进行了划分,所以可以对清除空间进行选择

4.G1HeapRegionSize,g1区会自动设置

5.cms达不到追求停顿时间的目的,cms只能说是尽可能减少。

6.crud 代码去实现, jvm最重要的关注点是思想

7.full gc也会去回收方法区的内容,回收效率非常低,所以后面换成元空间,不再当成对象。

8.三色标记?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值