每次GC需要扫描整个堆嘛?

238 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

每次GC需要扫描整个堆嘛?

知识储备:(详解还是要看JVM篇章)

一、垃圾回收大致分为三大类别

MinorGCMajorGCFullGC
触发条件Eden满了老年代满了1、OOM之前 2、System.gc() 3、老年代空间不足(大对象) 4、方法区(永久代)空间不足(后来使用matespace替换永久代之后就不会出现这种情况)
作用空间年轻代(复制算法)老年代(标记清除,标记整理)全堆空间
............

二、可达性分析法的实现过程

  1. 确定GCRoots。一般包含以下几个重要成分可能作为GCRoots

    1. 虚拟机栈和本地方法栈中引用的对象
    2. 堆中的字符串常量池和静态变量
    3. 。。。
  2. 从GCRoots开始遍历整个引用链,并将其标记为可存活。之后回收其他未被标记的即可

三、一个对象在堆的各个代中的流转过程(特殊情况除外:大对象等)

  1. 对象创建之初一般在年轻代的Eden区
  2. 当Eden满了之后触发MinorGC来将Eden和From区中可活对象放入To区。如果满了放入老年代。如果From中对象生存周期超过阀值则放入老年代
  3. 然后调转From区和To区的定义
  4. 如果遇到老年代空间满了就进行一次MajorGC。如果MajorGC之后还是不足就触发FullGC

问题一:根据不同的GC方式,扫描的区域也不同,也区别于不同的垃圾收集器。

  • Parallel:严格的年轻代和老年代,在回收的时候扫描固定区域
  • G1:针对分区算法,以及启动时配置的参数来跟踪并计算,在这个不超过最大时间间隔内回收哪些区的空间能做到最优。

问题二:一般对象创建之后就会出现在Eden区域,但是对于一些字符串常量、静态变量,则会出现在堆空间的字符串常量池中(字符串常量池是在JDK7之后才在堆中的)。对于一些Eden中存放不在的大对象可能会出现在老年代,此间可能会触发FullGC等情况

问题三:根据上述知识储备,不同的GC方式和不同的垃圾收集器,扫描的地方是不一样的,具体可以看知识储备。