堆内存中的分类:

新生代:伊甸园区,S0,S1——内存比8:1:1。
老年代:是新生代内存的两倍。

怎么知道是不是垃圾?

引用计数法:当一个对象被其他类引用时,就将引用数+1,初始为0。当触发GC的时候,该对象的引用数为0,则这个对象判定为垃圾。
可达性分析算法:通过一系列的GC roots向下搜索,搜索路径即为引用链,看对象有没有再引用链中,没在引用链中的判定为垃圾。
可作为GCroot的类:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象

    怎么清除垃圾?

    标记清除法:通过一定算法判断,将垃圾对象标记,然后全部清除
    标记整理清除法:在标记清除法的基础上,加一个整理的过程,为了更好的整理内存。
    复制清除法:将有用的对象复制到新的内存空间中,将原来的区域全部清除掉。
    压缩清除法:将存活对象压缩到一片内存空间中,剩余都是连续可用的内存空间,解决了内存碎片的问题
    YGC一般都是用的复制清除法。
    因为新生代中的百分之98都是垃圾,所有这种清除法被广泛应用。
    FUllGC一般采用标记整理法和压缩清除法。
    因为老年代对象较大,且常被引用,活下来的对象较多。并且没有新生代的S0和S1区。

    老年代空间担保原则

    在执行任何一次Minor GC之前,JVM都会先检查一些老年代可用的内存空间,是否大于年轻代所有对象的总大小。因为可能年轻代Minor GC之后,所有对象都存活下来了,年轻代所有伊甸园区对象全部进入老年代,如果说发现老年代内存大小是大于年轻代所有对象的,此时就可以放心地对发起一次YGC了。

    对象在堆内存的存活过程:

    1、当一个对象被创建,首先放入新生代的伊甸园区,伊甸园区内存满了之后触发YGC,将不是垃圾的对象复制到S0区,此时对象年龄+1。第二次触发YGC时,将伊甸园区和S0不是垃圾的对象放到S1区中,没躲过一次GC就将对象年龄+1。一个对象年龄到达15时放入老年代。
    2、当一个对象过大时(占用内存过多),直接放入老年代。
    3、动态年龄判断:根据对象年龄有另外一个策略也会让对象进入老年代,不用等待15次GC之后进入老年代,他的大致规则就是,假如当前放对象的Survivor,一批对象的总大小大于这块Survivor内存的50%,那么大于这批对象年龄的对象,就可以直接进入老年代了。

    什么时候触发GC?

    YGC:当伊甸园区内存不够时触发
    FULLGC:
    1、当老年区空间不足,方法区空间不足
    2、达到元空间设定阈值时~~~~
    新生代使用的是复制算法,为了内存利用率,只使用其中一个 Survivor 空间来做轮换备份,因此如果大量对象在 Minor GC 后仍然存活,导致 Survivor 空间不够用,就会通过分配担保机制,将多出来的对象提前转到老年代,此时如果老年代的可用内存小于该对象的大小,就会触发 Full GC。
    当老年代中最大可用的连续空间小于历代晋升到老年代的对象的平均大小时,会触发Full GC 来让老年代腾出更多的空间。
    image.png

    为什有GC机制还会出现OOM

    1、GC机制只能回收被判定为无用对象的回收,无法回收物理资源占用,比如数据库连接,IO流等内存占用
    2、GC的时机是可人为控制,无法精确的/最优的选择时机,当极端情况内存中存活得对象都是有用的则无法回收。

    用完大对象后想立即回收它应该怎么做,调用System.gc()之后会立即执行垃圾回收吗

    强制垃圾回收的两个方法:
    调用System类的gc()静态方法:System.gc()
    调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc()
    但是调用System.gc()只是建议虚拟机回收,具体回不回收是不确定的