JVM中GC原理解析

一、在理解GC之前,先了解下JVM体系结构

 

1.1什么是GC

GC可以理解为在追踪仍然使用的所有对象,并将其余对象标记为垃圾然后进行回收,这样的一个过程称之为GC,所有的GC系统可以从如下几个方面进行实现

1.GC判断策略(例如引用计数,对象可达)

2.GC收集算法(标记清除法,标记清除整理法,标记复制清除法,分带法)

3.GC收集器(例如Serial,Parallel,CMS,G1)

 

1.3手动GC

什么是手动GC呢?即是手动为对象分配内存并回收内存

如下这是一个简单的手动内存管理C编写的示例

int send_request() {
    size_t n = read_size();
    int *elements = malloc(n * sizeof(int));

    if(read_elements(n, elements) < n) {
        // elements not freed!
        return -1;
    }

    // …

    free(elements)
    return 0;
}

手动GC忘记释放内存是常有的事情。这样的话会直接导致内存泄露。

 

1.4自动GC

什么是自动GC呢?

自动GC一般是由系统自动对内存进行管理

 

引用计数法

 

其中:

1、绿色云表示它们指向的对象仍然由程序员使用。

2、蓝色圆圈是内存中的活动对象,其中的数字表示其引用计数

3、灰色圆圈是未从任何明确使用的对象引用的对象

对于引用计数法,有一个很大的缺陷就是循环引用,例如:

其中红色对象实际上是应用程序不使用的垃圾。但是由于引用计数的限制,它们不符合垃圾回收原理,所以仍然存在内存中,导致内存泄露。

 

标记清除法

标记清除通常有两个步骤:

1.标记正在遍历所有可达的对象

2.清除不可达对象占用的内存地址

 

这种方法就完美解决了对象之间循环依赖的问题,但是存在短时间的线程暂停。

 

二、JAVA中的GC分析

 

2.1、碎片与压缩

JVM在垃圾回收过程中可能会产生大量碎片,为了提供其读写性能,需要对碎片进行压缩

例如:

 

2.2、分代设想

我们知道垃圾收集要停止应用程序的运行,那么如果这个收集过程需要的时间很长,就会对应用程序产生很大的性能问题,如何解决这个问题呢?通过实验发现内存中的对象可以将其分为两大类:

1.存活时间较短(这样的对象比较大)

2.存活时间较长(这样的对象量比较小)

基于对如上问题的分析,通过了解科学家提出了分代回收思路(年轻代,老年代,永久代),同时缩小垃圾回收范围。

例如:

 

2.3、GC模式分析

垃圾收集事件(Garbage Collection events)通常分为:

1.Minor GC (小型GC):年轻代GC事件

2.Major GC(大型GC):老年代GC事件

3.Full GC (完全GC):整个堆的GC事件

 

三.GC算法基础

 

3.1、标记可达对象

现在的GC算法基本都是要从标记可达对象开始(Marking Reachable Objects)

例如:

GC一般会设置一些特定对象为GC的根对象,例如:

1.栈中的变量

2.常量池中的引用

.....

GC基于根对象标记可访问对象(蓝色表示),对于不可达对象GC会认为是垃圾回收对象。

 

3.2、移除不可达对象

移除不可达对象(Removing Unused Objects)时会因GC算法的不同而不同,但是所有的GC操作一般都可以分为三组:清除(Sweep),压缩(Compact),复制(Copy)

 

清除(Sweep)

 

压缩(Compact)

 

复制(Copy)

复制算法会基于标记清除压缩算法,创建新的内存空间用于存储幸存对象,同时可以复制与标记同时并发执行。这样可以较少GC时系统的暂停时间,提高系统性能

 

四、GC算法实现

现在对于JVM中的GC算法两大类:一类负责收集年轻代,一类负责收集老年代。假如没有显式指定垃圾回收算法,一般会采用系统平台默认算法,当然也可以自己指定,下面是JDK8中的一些垃圾回收算法应用组合如下:

Young

Tenured

JVM options

Serial

Serial

-XX:+UseSerialGC

Parallel Scavenge

Parallel Old

-XX:+UseParallelGC -XX:+UseParallelOldGC

Parallel New

CMS

-XX:+UseParNewGC -XX:+UseConcMarkSweepGC

G1

-XX:+UseG1GC

以上四种GC组合是现阶段最突出的几种方式。

 

4.1、Serial GC

Serial GC(串行收集器)应用特点:

1.内部只使用一个线程去回收(不能充分利用CPU的多核特性),无法并行化

2.GC过程可能会产生较长的时间停顿

3.Serial GC(串行收集器)算法应用:

3.1  新生代复制算法(新生代存活对象较少)

3.2 老年代标记-压缩算法(老年代对象回收较少,容易产生碎片)

Serial GC(串行收集器)场景应用:

a.应用在具体几百兆字节大小的JVM

b.应用在知有单个CPU的环境中

Serial GC(串行收集器)应用参数实践:

java -xx:+UseSerialGC com.mypackages.MyExecutableClass

Serial GC模式分析:

1.Minor GC

 

2.Full GC

 

4.2、Parallel GC

并行收集器应用特点:

1.可利用cpu的多核特性,可并行化执行GC操作。

2.在GC期间,所有cpu内核都在并行清理垃圾,所以暂停时间较短。

 

Parallel GC (并行收集器)算法应用:

1.在年轻代使用 标记-复制(mark-copy)算法:

1.在老年代使用 标记清除整理(mark-sweep-compact)算法

 

Parallel GC(并行收集器)场景应用:

1.应用于多核处理器,执行并行收集提高吞吐量。

2.GC操作仍需暂停应用程序,所以不适合低延迟场景

 

Parallel GC(并行收集器)模式分析:(事件分析)

1.Minor GC

 

2.Full GC

 

4.3、Concurrent Mark and Sweep (CMS)

即 标记-清除-垃圾收集器

CMS收集器特点:(避免在老年代垃圾收集时出现长时间卡顿)

1.使用空闲列表管理内存空间的回收,不对老年代进行整理

2在标记-清除阶段大部分工作和应用线程一起并发执行。

 

CMS算法应用:

1.年轻代采用并行STW方式的mark-copy(标记-复制)算法

2老年代主要使用并发 mark-sweep(标记-清除)算法。

 

CMS场景应用

1.应用于多核处理器,目标降低延迟,缩短停顿时间

2.cpu受限场景下,会与应用线程竞争cpu,吞吐量会减少

 

CMS关键阶段可以分为4个步骤:

1.初始标记 (CMS initial mark)

2.并发标记  ( CMS concurrent mark)

3.重新标记  ( CMS remark)

4.并发清除  (CMS concurrent sweep)

其中初始标记,重新标记这连个步骤仍然需要 "Stop The World" 初始标记仅仅只是标记GC Roots或yong gen能够直接关联到的对象,速度很快。

并发标记阶段就是进行GC Roots Tracin的过程,在此阶段,垃圾收集器遍历老年代,标记所有的存活对象,从前一阶段InitialMark找到的root根开始算起。

并发预清理(重新标记)阶段则是为了修正并发标记期间,因用户程序继续运作而导致冰机产生变动的那一部分的标记记录,这个阶段的停顿时间一般会比初始标记阶段长一些,但远比并发标记时间短。

在预清理阶段,这些脏对象会被统计出来,从他们可达对象也被标记下来,此阶段完成后,用标记的card也就会被清空。

 

并发清除此阶段与应用程序并发执行,不需要STW停顿。目的是删除未使用的对象,并回收他们占用的空间

 

由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行

 

4.4、G1-Gbage First

1.空间整理

 

2.可预测停顿

 

这里就不多说了,有想了解的小伙伴自己可以去了解呦!

转载请附上原创地址 谢谢。

  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值