JVM学习笔记——垃圾回收篇( 七 )


  1. RSet(Remember Set :记忆集合)
/*每一个Region都会划出一部分内存用来储存记录其他Region对当前持有Rset Region中Card的引用针对G1的垃圾回收时间设置较短,在进行标记过程中可能会导致时间过长,所以我们设置了RSet来储存部分信息我们可以直接通过扫描每块Region里面的RSet来分析垃圾比例最高的Region区,放入CSet中,进行回收 。*/
  1. CSet(Collection Set 回收集合)
/*收集集合代表每次GC暂停时回收的一系列目标分区 。在任意一次收集暂停中,CSet所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中 。年轻代收集CSet只容纳年轻代分区,而混合收集会通过启发式算法,在老年代候选回收分区中,筛选出回收收益最高的分区添加到CSet中 。*/新生代跨代引用由于我们的初次标记时会去寻找Root部分
但其实大部分的Root都放入了老年代,但老年底数据较多难以查找,所以G1提供了一种方法:
  • 将老年代O再次划分为多个区间,名为卡
  • 如果该卡中存储了Root部分,那么就将该卡标记为脏卡,同时放于RSet中存储起来便于查找
我们给出简单图示:
JVM学习笔记——垃圾回收篇

文章插图
同时如果该Root地址发生变化,G1给出了另外的方法进行更换:
  • 在引用变更时通过post-write barrier + dirty card queue
  • concurrent refinement threads 更新 Remembered Set
Remark重新标记我们在进行标记时通常采用三色标记法:
JVM学习笔记——垃圾回收篇

文章插图
我们做简单介绍:
  • 黑色是已经标记结束的内存
  • 灰色是正在标记的内存
  • 白色是未标记的内存
我们针对上述进行分析:
  • 最左侧是根,黑色,已经被标记
  • 上方为根的直接/间接引用对象,黑色,已经被标记
  • 下方为根的直接/间接引用对象,灰色,正在标记,白色,还未被标记当后面会被标记
  • 最右侧孤零零的白色方块,没有被引用,不会被标记,最后会被当作垃圾回收对象处理掉
这时我们就会发现一个问题:
  • 如果最右侧的方块在针对自身的CPU的并发标记结束后,又被其他进程所调用了(并发标记其他CPU正常运行)
  • 但是此时它是白色的,最终会被这次的垃圾回收操作清除掉,就会导致影响其他进程操作
所以我们设计了Remark重新标记操作:
  • 如果在该方块针对自身的并发标记结束后又被其他进程调用,这时将他拖入一个队列中,并将其变为灰色
  • 在并发标记结束后进入重新标记阶段,就会检查该队列,若发现灰色对象,在队列中将它变为黑色对象并排出队列
G1垃圾回收器重要更新下面我们将会针对G1垃圾回收器在各个版本的重要更新做个介绍
JDK 8u20 字符串去重我们首先要明白字符串在底层是采用char数组形成的:
String s1 = new String("hello"); // char[]{'h','e','l','l','o'}String s2 = new String("hello"); // char[]{'h','e','l','l','o'}如果重复的字符串都存放在内存中肯定会导致内存多余占用,所以提供了解决方案:
  • 将所有新分配的字符串放入一个队列
  • 当新生代回收时,G1并发检查是否有字符串重复
  • 如果它们值一样,让它们引用同一个 char[]
  • 注意与 String.intern() 不一样:一个底层针对String类型,一个底层针对char[]类型
其优缺点: