java垃圾回收

1. 什么是垃圾

通过【根搜索算法(GC Roots Tracing)】判定。当GC Roots与某个对象不可达时,则认为这个对象是可回收的对象

java垃圾回收_第1张图片
java垃圾回收_第2张图片

可作为GC Root的对象:

  1. 虚拟机栈(栈帧中的本地变量表)中的引用的对象
  2. 方法区中的类静态变量引用的对象
  3. 方法区中的常量引用的对象
  4. 本地方法栈中的引用的对象(本地方法:简单地讲,一个Native Method就是一个非java实现的方法,从而借助其他语言完成java无法完成或效率低的工作)

2. 如何回收垃圾

  1. 标记-清除算法(mark sweep)
    java垃圾回收_第3张图片
    标记所有要回收的对象,在回收时统一回收
    优点:逻辑简单
    缺点:标记和回收的效率都不高;会造成大量的内存碎片,导致无法找到足够大的连续内存而触发垃圾回收。
  2. 复制算法
    java垃圾回收_第4张图片
    内存按容量大小平均分为两块,每次只使用其中一块。当这一块用完后将存活着的对象复制到另外一块,然后把已使用的内存空间一次回收掉。
    优点:不存在内存碎片问题,实现简单,运行高效
    缺点:导致可用内存变为原来的一半。
  3. 标记整理算法
    java垃圾回收_第5张图片
    让所有存活的对象向一端移动,然后直接回收端边界以外的内存。
    优点:解决了内存碎片问题
    缺点:内存变动频繁,效率很低
  4. 分代回收算法
    java垃圾回收_第6张图片

该算法通过以下五个策略对堆内存进行管理,其中对年轻代使用复制算法回收,对老年代使用标记整理算法回收。

  1. 对象优先在Eden分配。 当Eden区没有足够的空间进行分配时,JVM发起一次Minor GC;通过 Minor GC 之后,Eden 会被清空,Eden 区中绝大部分对象会被回收,而那些无需回收的存活对象,将会进到 Survivor 的 From 区(若 From 区不够,则直接进入 Old 区)。
  2. 大对象直接进入老年代。 避免大对象在Eden区及两个Survivor区发生大量的内存复制。
  3. 长期存活对象进入老年代。 每个进入Survivor区的对象年龄设定为1,并且对象在 Survivor 区中每经历一次 Minor GC,年龄就增加1岁。当年龄增加到15岁时,这时候就会被转移到老年代。对象晋升老年代的阈值,可以通过-XX:MaxTenuringThreshold来设置。
  4. 动态对象年龄判定。 如果Survivor空间中年龄1-X的对象占用空间总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。
  5. 空间分配担保。 当发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小。如果小于,则改为直接进行一次Full GC。如果小于,则查看HandlePromotionFailure设置是否允许担保失败;如果允许,那么只会进行Minor GC;如果不允许,则进行一次Full GC。

注:

  • 关于动态年龄判定,jvm误区–动态对象年龄判定讲得非常棒
  • 新生代GC(Minor GC):发生在新生代的垃圾回收动作,因为java对象大多具有朝生夕死的特性,所以Minor GC非常频繁,一般回收速度也比较快
  • 老年代GC(Major GC):发生在老年代的GC。Major GC一般会比Minor GC慢10倍以上。
  • 以上内容参考《深入理解Java虚拟机》及 咱们从头到尾说一次 Java 垃圾回收

你可能感兴趣的:(java垃圾回收)