JVM GC总结

判断对象存活

引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1,引用失效时,计数器就减1;任何时刻计数器都为0的对象就是不可能再被使用的。

问题:无法解决对象之间的相互循环引用

根搜索算法(java,c#,List)

通过一系列的名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索通过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

在java中,GC Roots对象包括

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

    只要强引用还在,就不会被回收
    "Object obj = new Object()"

  • 软引用

    在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围并进行第二次回收。

  • 弱引用

    被弱引用关联的对象只能生存到下一次垃圾收集之前

  • 虚引用

    一个对象是否有虚引用不对其生存时间构成影响

垃圾收集算法

多个算法一起工作

分代收集算法

根据对象的存活周期的不同将内存划分为几块。一般是把java堆分为新生代老年代。新生代适合选用复制算法,老年代对象存活率高,没有额外空间分配担保,就必须使用“标记-清理”或“标记--整理”

复制算法

将可用内存按容量分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另外一块上面,然后把已使用过的内存空间清理掉

在虚拟机的实现中,将新生代分为一块较大的Eden空间和两块较小的Survior空间(8:1:1),每次使用Eden和其中的一块Survivor。当回收时,将Eden和Survivor中还存活的对象一次性的拷贝到另外一块Survivor,最后清理掉Eden和刚才的Survivor.

  • 内存分配

    • 对象优先在Eden分配,一次gc后进入Survivor

    • 大对象直接进入老年代

      避免Eden与两个Survivor区之间发生大量的内存拷贝

    • 长期存活的对象将直接进入老年代

      对象年龄计数器,经过15次gc而不死

标记-清除

首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象
问题:
效率低,产生大量内存碎片

标记-整理算法

让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

垃圾收集器

Serial Serial Old ParNew Parallel Scavenge Parallel Old
单线程 单线程 多线程 多线程 多线程
新生代 老年代 新生代 新生代 老年代

CMS

并发收集,低停顿,标记-清除算法

G1

之前的收集器进行收集的范围都是整个新生代或老年代,而G1将整个java堆(包括新生代,老年代)划分为多个大小固定的独立区域,并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域。

回收方法区

  • 废弃常量
  • 无用的类
    • 该类所有实例已回收
    • 加载该类的ClassLoader已回收
    • 该类对应的Class对象没有在任何地方被引用
原文地址:https://www.cnblogs.com/lifan1998/p/10362038.html