Java垃圾回收机制

如何判断一个对象是否已经死去

  1. 引用计数法,只有有一个地方引用,计数器就加1,引用失效就减1
  2. 可达性分析:以GC Roots的对象作为起始点,从这些节点向下搜索,所走过的路径成为引用链,当一个对象到GC Roots没有任何引用链,则该对象不可达,可回收。

GC Roots对象有哪些

  1. 虚拟机栈中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中JNI引用的对象

引用的分类

  • 强引用:用过new出来的引用,只要强引用还存在,则不会回收。
  • 软引用:通过SoftReference类来实现,用来描述一些有用但非必需的对象。
  • 弱引用:非必须对象,通过WeakReference类来实现,被弱引用的对象,只要发生GC就会被回收。
  • 虚引用:通过PhantomReference类来实现,无法通过虚引用获得对象的实例,唯一作用就是在这个对象被GC时会收到一个系统通知。

垃圾回收算法

标记-清除

  • 标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
  • 缺点:
    • 标记和清除两个过程效率都不高。
    • 标记清除后会有大量的内存碎片。

复制算法

  • 将内存划分为 大小相同的两块,每次只使用其中一块。当一块内存用完,就将还存活的对象复制到另一块,然后把已经使用过的内存空间清除。
  • 大部分商业虚拟机都使用这种算法回收新生代,但不是使用1:1的比例,而是一块较大的Eden空间和两个较小的Survivor空间上,每次使用Eden和其中一块Survivor。当回收时,将还存活的对象复制到另一块Survivor上,然后清理两块空间。HotSpot使用8:1:1.

标记-整理

  • 先标记出所有需要回收的对象,让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
  • 老年代使用这种方法。

分代收集

  • 根据对象存活周期的不同将内存划为几块。一般java堆分为新生代和老年代,这样可以根据不同年代的特点采用适当的收集算法。
  • 新生代中每次垃圾回收都会有大量对象死去,只有少量存活,那就用复制算法,只需要付出少量存活对象的复制成本。老年代中对象存活多,所以必须使用标记清理或者标记整理算法。

输入图片说明


输入图片说明


对象分配规则

  1. 对象优先分配在Eden区,如果空间不足就执行一次Minor GC。
  2. 大对象直接存入老年代(大对象时指需要连续内存空间的对象)。这样做是为了避免在Eden和Survivor之间发生大量的内存拷贝。
  3. 长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,经过一次MinorGC后会进入Survivor区,后每经过一次MinorGC年龄加1,直到到达阈值对象进入老年代。
  4. 动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
  5. 空间分配担保。每次进行MinorGC时,JVM会计算Survivor区移动到老年区的对象平均大小,如果这个值大于老年区的剩余大小则进行一次FULLGC,小于则检查HandlePromotionFailure设置,如果true则只进行MinorGC,如果true则进行FULL GC。

猜你喜欢

转载自my.oschina.net/u/1046919/blog/1539629