JVM原理之垃圾收集

来源:互联网 发布:python 搜索引擎 编辑:程序博客网 时间:2024/05/18 06:08

垃圾收集作用

  1. JVM堆中存在大量的垃圾对象,如果长时间不收集,容易造成内存溢出或者内存泄露。垃圾收集可以减少堆的可用空间。
  2. 频繁的GC行为会造成应用程序的停顿,造成用户体验较差,吞吐量减少。

确定回收对象

  1. 引用计数器:为每个对象设置一个引用计数器,当该对象被引用时,计数器加1,没有任何引用时,计数器减1。当计数器为0时,即没有任何对象引用这个对象,即可回收。这种方式简单粗暴,不能解决两个对象互相引用问题。比如,objA.instance=objB;objB.instance=objA;JVM中没有使用此算法。
  2. 可达性分析算法:JVM中从成为”GC Roots”的对象为起点,从GC Roots的对象往下搜索,搜索过的路径称之为链,如果一个对象obj到GC Roots没有任何链路可达,则认为该对象是垃圾对象,将被回收。
    2.1. 一定是该对象到GC Roots之间没有可达的引用链,而不是几个对象之间引用。可以通过下图具体说明:
    这里写图片描述
    2.2. GC Roots的对象:在JVM中一般认为如下是GC Roots的对象。

  3. 虚拟机栈的栈帧中的本地变量表中引用的对象

  4. 方法区中类的静态变量或常量引用的对象
  5. 本地方栈中JNI引用的对象。
    2.3. 对于GC Roots的对象,引用网络一位同学的图片,很好的解释GC Roots的对象是啥
    这里写图片描述
    2.3.1. 从图中可以看出,reference1,reference2,reference3是GC Roots
    2.3.2. 对象实例1,对象实例2,对象实例4是GC Roots的对象,视为存活对象
    2.3.3 对象实例1,对象实例2,对象实例4,对象实例6属于可达对象
    2.3.4. 对象实例3,对象实例5则为不可达对象,将会被JVM垃圾回收。

垃圾回收算法与思想

1 . 标记-清除算法: 这个算法分为两个阶段,第一阶段是标记阶段,从GC Roots的对象寻找到可达对象,然后做好标记;不可达对象则是垃圾对象。第二阶段是清除阶段,将第一阶段中未被标记的对象一次性清除。
1.1. 缺点一:JVM堆的空间物理上不是连续的,而是逻辑上连续的,但是对象的存储需要一个连续的物理空间。标记-清除算法回收后的空间容易出现不连续,碎片太多。遇到大对象,需要再一次回收。
1.2. 缺点二: JVM堆分为年轻代和老年代,大部分对象都是在年轻代就死亡,在年轻代很容易造成不连续空间,连续空间的效率明显高于非连续空间。
标记-清除算法示例
2. 复制算法: 鉴于标记-清除算法的缺点,即回收之后容易造成很多内存碎片(不连续的空间)。复制算法核心思想是,将堆内存划分为两块大小相等的区域M1,M2,平时只是使用其中一块内存空间M1。发生GC行为时,将正在存活的对象复制到另外一块内存区域M2,然后将M1的所有对象全部清除。完成M1,M2角色呼唤。
2.1. 优点: 垃圾对象往往比较多,存活对象较少,复制的对象其实较少,效率高。同时,M1空间回收完毕后,没有碎片空间,都是连续的。
2.2 缺点:从复制算法核心思想来看,需要将内存空间折半处理。有点浪费空间。复制算法的高效性是建立在垃圾对象多,存活对象少的前提之下,在年轻代可以使用复制算法,但是在老年代属于垃圾对象少,存活对象多。复制算法效率很低。
复制算法
2.3 适用场景:复制算法适合年轻代垃圾收集,在年轻代,垃圾对象多,存活对象少。
3. 标记-整理算法:鉴于复制算法的优缺点,可以发现复制算法不适用于老年代垃圾回收。对于老年代垃圾回收,采用标记-整理算法较为合适。标记-整理算法核心思想与标记-清除相似,需要将存活对象先打上标识,然后将存活对象全部移动到内存另外一端,最后再将边界以外的对象全部清除。
3.1. 优点:不需要将内存折半,回收后空间又是连续的,没有碎片。
标记-整理算法

分代收集

  1. 分代收集算法:就是年轻代与老年代采用不同的回收算法,这种分而治之的思想能够根据不同区域的垃圾对象采取不同的解决方案。
  2. 年轻代回收算法:年轻代由于垃圾对象多,存活对象少,频繁创建对象较多,而且年轻代通常分为Eden区,from surivior(s0)和to surivior(s1)区;s0和s1大小相同,适合采用复制算法实现。
  3. 老年代算法:老年代属于存活对象较多,甚至大量存活对象,适合采用标记-整理算法。

回收算法总结

这里写图片描述

垃圾收集器

  1. 主流的JVM进行GC时都是分代垃圾收集算法,则对于不同的收集算法实现的垃圾收集器主要有哪些呢?
  2. 垃圾收集器在进行GC时会产生应用停顿,对于采用不同回收算法实现的垃圾收集器在GC时对应用造成什么样的影响?
  3. 每一种垃圾收集器又有什么特点呢?
  4. 先通过一张图总体来看当前各种垃圾收集器的关系:
    这里写图片描述

5.Serial收集器:Serial收集器是一个新生代单线程收集器,采用复制算法实现,发生GC时会发生STW(stop the world)。现在已经不使用,不作过多介绍。可以与CMS,Serial old使用。
- Parnew收集器: Parnew收集器是一个新生代多线程收集器,采用复制算法实现,发生GC时,会暂停所有用户线程。但是它是唯一个可以与CMS配合使用的新生代多线程收集器。
- Parallel scavenge: 它也是一个新生代多线程收集器,采用复制算法实现。发生GC时,会发生暂停所有用户线程。该收集器不能与CMS配合使用。
7.1. 特点:重点关注系统的吞吐量,以提高系统吞吐量为目标。该收集器通过两个参数 -XX:MaxGCPauseMills和-XX:GCTimeRatio控制系统的目标。
7.1.1. -XX:MaxGCPauseMills:垃圾回收时最大停顿时间,收集器进行垃圾回收时尽量控制收集时间不超过此设定值。但是如果设置过小,会牺牲吞吐量和减少新生代生存空间
7.1.2. -XX:GCTimeRatio设置系统吞吐量的大小,这个数值是0到100之间的整数。假设GCTimeRatio为N,则 系统GC时间不能超过1/(1+N),默认下该值为99
7.1.3. -XX:UseAdaptiveSizePolicy:打开这个参数,不需要手工设置其他参数。只需要设置堆大小,Eden,Surivior的比例即可。垃圾收集各种交给parallel去完成。虚拟机会动态调整垃圾收集和吞吐量
- Serial old收集器: 老年代单线程垃圾收集器,采用标记-整理算法实现。现在通常作为CMS的备用收集器。发生GC时暂停用户线程。
- Parallel old收集器:老年代多线程垃圾收集器,采用标记-整理算法实现。它能与Parallel scavenge配合使用。它也是关注系统的吞吐量,这对组合收集器都是关注吞吐量优先,在注重CPU敏感场景使用它。发生GC时,暂停用户线程
9.1 特点一:发生GC时暂停用户所有线程。可以使用-XX:+UseParallelOldGC表明新生代和老年代都使用多线程收集器。
9.2 特点二:线程数量可以使用-XX:ParallelGCThreads指定线程工作数量,一般与CPU核数相等。超过8核,则设置为3+5*cpu/8
10. CMS收集器:CMS收集器注重用户停顿时间,以提高用户线程停顿时间为目标。即提升服务器的响应速度。在互联网应用中使用很多。采用标记-清除算法实现。发生GC时,用户线程与GC线程交叉运行
10.1 CMS收集流程

  • 初始标记:这阶段会发生STW(stop the world).
  • 并发标记:用户线程交叉运行
  • 重新标记:这个阶段发生STW。
  • 并发清除:用户线程交叉运行。
    10.2 设置使用CMS收集器:

  • -XX:+UseConcMarkSweepGC表明新生代使用并行收集器,老年代使用CMS收集器

  • -XX:ParallelCMSThreads设置CMS线程数
    10.3 CMS缺点

  • 对CPU资源敏感:所有的并发程序都对CPU资源特别敏感。CMS运行期间,虽然用户程序能够并发运行,但是在初始标记,重新标记阶段发生STW,造成系统吞吐量降低。CMS默认启动垃圾回收线程数量为(CPU数量+3)/4。

  • 无法处理浮动垃圾:CMS是并发收集,即JVM使用CMS进行GC时,用户线程不停顿,与垃圾回收线程交替运行。
  • 必须预留空间:用户线程在运行期间,同样会产生垃圾对象,然而垃圾回收线程是不会在此次收集还未标记过的垃圾。由于CMS这种特性,所以CMS不会等到老年代空间几乎装满的时候再收集,需要预留出一部分空间供GC时用户程序使用。
  • 收集失败:在JDK6以后,CMS的阈值已经提升到92%。如果CMS在发生GC时预留的空间不足,则会发生并发模式失败(Concurrent Mode Failure)。此时JVM会选择Serail old作为备用垃圾收集器,这样就容易造成系统吞吐量大幅降低。
  • 收集算法:CMS采用的标记-清理算法,采用标记-清理算法的后果就是GC完后,容易产生大量的不连续的内存碎片。遇到大对象存储时,还会再次出发一次Full GC。为了解决这个问题,CMS提供了-XX:+UseCMSCompactAtFullCollection开关参数,默认开启。当CMS因为空间不足要提前触发Full GC时,进行碎片整理。这个工作不能并发执行,造成STW。另外CMS还提供了-XX:CMSFullGCsBeforeCompaction,这个参数用于设置进行多次Full GC时(默认值为0),再进行一次Full GC时包含碎片整理的过程。

垃圾回收策略

  1. 对象优先分配在Eden区域
  2. 大对象直接进入老年代
    这里写图片描述
  3. 长期存活对象直接进入老年代
  4. 动态对象年龄判断
    这里写图片描述
原创粉丝点击