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[]类型
其优缺点:
  • 优点:节省大量内存
  • 缺点:略微增多了CPU时间 , 新生代回收时间略微增多
JDK 8u40 并发标记类卸载当所有的类都经过并发标记后,就会直到哪些类不再被使用
这时如果一个类加载器的所有类都不再使用时,我们就可以卸载它所加载的所有类
JDK 8u60 回收巨型对象首先我们介绍一下巨型对象的定义:
  • 一个对象大于 region 的一半时,称之为巨型对象
    然后我们再来介绍G1对巨型对象的处理方法:
  • 回收时被优先考虑
  • G1 不会对巨型对象进行拷贝
  • G1 会跟踪老年代所有 incoming 引用,这样老年代 incoming 引用为0 的巨型对象就可以在新生代垃圾回收时处理掉
垃圾回收调优本小节将会介绍垃圾回收的调优机制
基本调优概念我们进行调优需要掌握的基本知识:
  • 掌握相关工具使用
  • 掌握基本的空间调整
  • 掌握GC相关的VM参数
  • 明白调优并非固定公式 , 而是需要结合应用,环境
我们调优的领域并非只有垃圾回收,但是这个部分的调优确实会给项目带来很大的速率优化 , 此外还有其他方法的调优:
  • IO调优
  • 锁竞争调优
  • CPU占用调优
此外我们需要确定调优的目标:
  • 是为了保证低延迟还是为了保证高吞吐量
最快的GC是不发生GC首先我们需要明白GC是花费时间的,如果我们能够控制好内存保证不发生GC,那么才是最快的
如果我们频繁发生GC操作 , 那么我们就需要先进行自我反思:
  1. 存放的数据是否过多?
/*例如我们是否设置了相同元素筛?。看砦笳撕沤够捍妫?*/
  1. 数据表示是否臃肿?
/*例如我们调取数据时是否只调取了我们所需数据还是全盘托出?例如我们选择数据类型时是否是以最低标准为要求,数据库能采用tiny不要使用int*/
  1. 是否存在内存泄露?
/*例如我们是否设置缓存数据时采用了Static形式的Map并不断存储数据?*/新生代调优首先我们先来回顾一下新生代的优点: