深入理解java虚拟机-垃圾收集器(3)

怎么判定一个对象是死的呢?

目前有引用计数法,和根搜索法

引用计数法 即改对象被引用的次数,弊端 循环引用的问题,如 studenta.instance=studentb,studentb.instance=studenta

Hotspot采用的是根搜索法(可达分析法),当一个对象到GCRoot 没任何引用相连,则该对象可被回收

可做GCRoot,有静态变量,栈中引用对象,常量引用,本地方法栈引用的对象.

 

官方文档 关于垃圾回收https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html

垃圾回收主要分三类

1:标记清除算法,MarkSweep,把所有垃圾对象做标记,然后直接清楚

2:复制算法,比如分两块同等大小内存,把A中存活的对象复制到B,然后清除A,

3:标记整理算法,MarkCompact,把垃圾对象清楚后,然后向一段移动,以防止内存碎片。

 

JVM中进行垃圾回收,会出现stop the world 即停顿所有正在工作的线程,不然引用关系会发生变化。

安全点:虚拟机需要知道哪些对象是引用,使用一个为OopMap数据结构来进行记录,类加载完后HotSpot就把对象内什么偏移量上是什么类型数据计算出来,JIT编译中也会记录下哪些位置是引用,Hotspot可以通过oopmap完成快速gcroot枚举,只有在一些特定的地方才会生成oopmap(称为安全点)方法调用,循环跳转,异常跳转等才会产生安全点。当方式gc的时候所有线程去轮训一个flag,如果出现gc flag,则所有线程到最近的安全点停下。

安全区域:如果线程处于阻塞或者sleep的时候无法到安全点的,这个时候线程标识自己进入了安全区域,当出安全区域的时候

要检查是否在进行gcroot枚举,如果是继续等待。

 

 

新时代收集器

serial:单线程收集器,复制算法(这个参数新时代老年代都是串行) -XX:+UserSerialGC

 

parNew:是serial的多线程版本 复制算法 (新时代使用一般搭配CMS使用) -XX:+UseParNewGC

同时可以指定-XX:ParallelGCThreads来设置并行的线程数量

 

parallel scavenge:复制算法,也是并行的多线程版本,但是侧重点不一样,这个收集器注重throughtput(吞吐量)

即cpu运行用户代码时间/(用户代码+垃圾回收)

可以通过-XX:MaxGCPauseMillis来设置最大停顿时间

也可以设置吞吐量 -XX:GCTimeRatio来设置吞吐量默认99

由jvm来动态调整新时代大小和eden和survivor比例   -XX:UseAdaptiveSizePolicy(默认开启1.7)

 

老年代收集器

serial old收集器单线程收集器

 

parallel old 多线程老年代收集器    -XX:+UserParallelOldGC(新老都是用parallel 收集器) 

 

CMS 并发(用户程序和垃圾并发)老年代收集器

 

对于这个重新标记 ,翻阅了很多文档,由于水平有限,把自己的理解说下。

当在并发标记阶段的时候,用户线程和gc线程是一起工作的,其中新生代对象升到老年代,或者老年代的对象被重新引用,或者在老年代分配对象,这个时候就要记录下这些对象(预清理阶段),并且使用一个数据结构记录下这些对象,并且标记为dirty,

目的是标记可达的老年代对象和标记引用修改那些dirty的。在重新标记阶段,遍历整个新生代区域(因为并发阶段新生代的对象是不但在变化的),进行对象标记,遍历老年代中的那些被标记为dirty的(重新trace标记相关的对象),然后执行并发清理,

在并发清理阶段,也会产生新的对象的,这样对象是没有被标记的,存放在一定区域,这些对象在当前垃圾回收的时候是不会被回收的。

jdk官方文档https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html

  • 其中有这么一段话,暂停用户线程,并且重新标记那些被更改的  部分roots节点 和对象,(重新标记并不会重新扫描整个老年代,不然就么意义了。)

  • Stop all application threads and retrace sections of the roots and object graph that may have been modified since they were last examined, and then resume all application threads.

  •  

使用cms (一般搭配parnew)如果你cpu核心教少 可能会影响你执行代码的时间 -XX:+UseConcMarkSweepGC

-XX:CMSInitiatingOccupancyFraction=80用来设置当老年代内存达到使用到百分之80的时候,开始进行gc,

因为在并发清理阶段,还是会产生垃圾,需要预留一定空间给用户

 

由于cms收集器是 并发清除的收集器,会产生垃圾碎片,所以提供了一个-XX:+UseCMSCompactAtFullCollection(默认开启)

进行FullGC的时候开启内存碎片的整理,

同时还有一个参数-XX:+CMSFullGCsBeforeCompaction=0 意思是执行多少次不压缩的FullGC后执行一次带压缩的FullGC

 

知识点:

虚拟机还提供设置当大于某一个值的对象之间 放到老年代

-XX:PretenureSizeThreshold=1024*1024 (参数是不支持乘法的,只是更加直观表示大于1M的对象之间进入老年代)

 

-XX:MaxTenuringThreshold=15     (默认值)设置新生代经历多少次minorGC才能进入老年代

 

当survivor中相同年纪存活的对象大于survivor空间的一半的时候,年纪大于或者等于当前年纪的对象直接进入老年代

 

空间担保分配:

当新生代minorGC,如果对象的大小 小于老年代的空间,当minorGC是安全的

如果大于当前老年代的空间,那就需要看-XX:-/+HandlePromotionFailure(-关闭,+开启)

如果允许担保,那么就先检查历次从survivor升到老年代的平均大小是否 大于当前survivor中值

如果大于 则尝试进行minorGC,如果小于或者不允许担保则FullGC

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值