自动垃圾收集机制

java的GC机制是和其内存模型相关联的,而GC的核心内存区域是内存中的堆区。

java堆区按对象的存活时间被分为了年轻代(eden区+s0区+s1区)和老年代(tentired区),java堆的按代区分其实是为了其垃圾回收的分代收集机制打开了方便之门。java的GC收集器会在不同的分代上使用不同的垃圾收集策略。

GC其实主要需要解决两个问题:哪些是垃圾?如何清理垃圾?

在解决这两个问题上涉及到下面的方法论:

1.垃圾对象判定方法

  引用计数法:在C++的智能指针中使用了这种方式去做内存的自动回收。即在对象生成时维护一个对该对象引用次数的计数器,对象初次生成时计数器值为1,每增加一个到该对象的引用,计数器加1,每减少一个引用(如引用变量赋值null,或引用变量离开作用域),计数器减1,计数器为零时,对象内存会被自动回收。该方法的问题是存在内存泄漏的隐患,如对象相互引用、循环引用等情况

  可达性分析法:通过一系列的称为 “GC Roots” 的对象作为起点,搜索这些节点引用的对象,以及这些引用对象内部属性引用的对象,相当于从一个树形结构的根部进行遍历。节点所走过的路径称为引用链,当一个对象处于引用链上,就被判断为可用对象。其它的对象就是要被清理的无用对象。目前jvm都是采用这种方式进行垃圾对象的判断的。

补充说明:引用计数和可达性分析我觉得有点像黑名单和白名单两种思路。引用计数的方式采用了黑名单的方式来处理问题,把计数为零相当于一个黑名单条件,满足条件的对象是需要清理的垃圾对象,处于黑名单中。可达性分析法是将处于引用链的对象加入白名单,白名单外的对象被清理。我们在进行数据过滤时经常会用到黑白名单的思路,白名单由于对有效数据的限制条件更严格,这种过滤方式往往也更精确。

2.垃圾对象清理方法

  java在GC过程中会依据年轻代和永久代中对象的不同特点采用不同的对象清理方式,即所谓的分代收集策略,其中涉及到的方法有下面几种。

2.1 标记-清除算法:

  通过可达性分析方式找到所以需要回收的对象,并进行标记,在标记完成后统一回收所有被标记的对象。

  主要问题是容易参数内存碎片。

2.2 复制算法

  它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。

  目前java堆中的年轻代在进行young GC时采用的这种方式,其中划分出的两块内存s0区和s1区就是这样用的,每次GC都会切换身份,一个存放存活对象,一个存放新生对象。

2.3 标记-整理算法

  标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。以此避免内存碎片。

java堆的老年代一般采用这种方式进行GC

 java中采用分代收集:

新生代采用 复制算法

 老年代 标记整理

 垃圾收集器:

串行:

 并行:

 并发

g1收集器

  Serial 收集器:单线程,新生代采用复制算法,老年代采用标记-整理算法。
  ParNew 收集器:Serial 收集器的多线程版本,新生代采用复制算法,老年代采用标记-整理算法。
  Parallel Scavenge 收集器:多线程,新生代采用复制算法,老年代采用标记-整理算法。
  Serial Old 收集器:Serial 收集器的老年代版本,单线程
  Parallel Old 收集器:Parallel Scavenge 收集器的老年代版本,多线程
  CMS 收集器:多线程,并发收集,标记-清除
  G1 收集器:多线程,并发收集,复制加标记整理

原文地址:https://www.cnblogs.com/cxyxiaobao/p/12397918.html