java中的GC收集器详情

目录
  • 1、GC(Garbage collection )
  • 2、GC算法
    • 2.1标记活动对象
    • 2.2 删除空闲对象
    • 2.3 标记清除(Mark-Sweep)
    • 2.4 清除压缩(Mark-Sweep-Compact)
    • 2.5 标记和复制
  • 3、JVM GC
    • 3.1 JVM GC事件
    • 3.2 Serial GC
    • 3.3 Parallel GC
    • 3.4 Concurrent Mark and Sweep
    • 3.5 G1 –垃圾优先
  • 4、总结

1、GC(Garbage collection )

程序内存管理分手动和自动。

手动内存管理,需要我们编程的时候显式分配和释放空间,但如果忘记释放,会造成严重的内存泄漏问题。如下:

//申请40MB内存
 int* p = malloc(1024 * 1024 * 10 * sizeof(int));
 //释放内存
 free(p);

显式分配和释放很容易就造成内存泄漏。因此我们希望有一种能自动回收内存的方法,这样就可以消除人为造成的错误。我们将这种自动化称为垃圾收集(简称GC

现代高级编程语言基本上都具备GC功能。

2、GC算法

GC算法按照下面两方面内容设计

  • 标记出所有活动对象(程序正在使用或者叫可达对象);
  • 删除未使用的对象和重新整理空间。

2.1标记活动对象

java gc 通过追踪活动对象进行标记,未被标记的对象为空闲状态。空闲状态对象将会在清理阶段被回收。

GC标记对象是从GcRoots开始,它是一类特殊对象,分以下几种:

  • 当前执行方法中的局部变量和方法参数。
  • 活动Java线程。
  • 静态变量由其类引用。不过类本身是可以被垃圾收集,回收时将删除所有引用的静态变量。
  • JNI引用是本机代码作为JNI调用的一部分创建的Java对象。这样创建的对象将被特别对待,因为JVM不知道本机代码是否正在引用它。

标记开始时,GC会遍历内存中的整个对象树,从那些GC Roots开始,然后是从根到其他对象(例如实例字段)的引用。GC访问的每个对象都 标记 为活动对象。

标记结束后,如下图所示,蓝色表示为GCroots仍然在引用的对象,灰色表示为空闲对象等待回收。

标记阶段需要注意两方面:

  • 标记需要暂停应用程序线程,这很好理解如果应用线程一直在运行对象活动状态就会一直变化,GC就无法进行标记。这种情况称为 安全点, 导致 Stop The World暂停简述为(STW)。
  • 暂停的持续时间受活动对象的数量影响,不取决于堆的大小和对象总数 。 因此,增加堆大小不会直接影响标记阶段的持续时间。

2.2 删除空闲对象

GC删除空闲对象的一般分为三类:

  • 清除,
  • 压缩,
  • 复制。

2.3 标记清除(Mark-Sweep)

经历标记阶段后,所有空闲对象占用的空间都可以重新分配新对象了。它会维护一个空闲列表,里面记录的空闲区域的位置和大小。这种方式的缺点很明显一是维护空闲列表增加对象开销,二是空闲区域大小不均匀,可能会遇到分配大对象区域不够存储的情况。

2.4 清除压缩(Mark-Sweep-Compact)

清除压多了一步复制动作弥补标记清除的缺点。它将所有活动对象移动到内存区域的开头。不过该方式的缺点是增加复制动作,也就增加了GC暂停时间。

2.5 标记和复制

标记复制这种方式与上面标记清除压缩相似,区别在于它是将活动对象复制到另外一块新的区域(幸存对象区域)。它的好处在于复制动作可以与标记阶段同时进行,缺点是需要另外一个存储区域,该存储区域应足够大以容纳幸存的对象。

3、JVM GC

在较旧的JVM GC中(串行,并行,CMS)将堆分成三个部分:固定内存大小的年轻代,年老代和永久代。

JVM使用两种GC算法分别对年轻代和年老代对象进行回收。年轻代的进行标记复制操作,年老代回收进行标记清除压缩。

3.1 JVM GC事件

我们把GC清除堆不同区域的触发事件分为以下几种:

  • Minor GC 从年轻代空间回收称为次要GC。
  • Major GC 从年老代空间回收主要GC。
  • Full GC 清理整个堆空间,包括年轻代和年老代。

3.2 Serial GC

串行GC,年轻代进行标记复制,年老代进行标记清除压缩。两个GC都是单线程操作,并且触发STW,停止所有应用线程。多CPU计算机中基本不会使用这个GC收集器。只有在单CPU的服务器上使用才有意义。

java -XX:+UseSerialGC

3.3 Parallel GC

并行GC,年轻代进行标记复制,年老代进行标记清除压缩。不管是年轻代还是年老代GC时都会触发STW,停止所有应用线程。与串行GC的区别在于它是使用多个线程运行标记和复制/压缩,多线程可以缩短GC收集时间。

java8默认GC收集器就是 parallel gc。不过因为它在标记清理阶段仍然需要停止应用线程,所以在要求较低延迟的场景下可能变得不那么适用。

可以通过-XX:ParallelGCThreads = NNN指定处理的线程数量 。默认值等于计算机中的内核数。

java -XX:+UseParallelGC #使用并行垃圾收集进行清理
java -XX:+UseParallelOldGC #将并行垃圾回收用于。启用此选项会自动设置-XX:+ UseParallelGC
java -XX:+UseParallelGC -XX:+UseParallelOldGC

3.4 Concurrent Mark and Sweep

并发标记扫描(CMS),年轻代空间执行并行标记复制,年老代空间执行并发标记清除。年轻代GC时触STW,停止所有应用线程,然后多线程并行收集。年老代并发标记清除不需要暂停应用线程。它的意义在于着避免了Parallel GC收集器在年老代GC时的长时间停顿。

默认情况下,此GC方式使用的线程数等于计算机物理内核数的1/4。

java -XX:+UseConcMarkSweepGC

我们看下CMS经历的几个阶段

(1)初始标记,暂停应用线程,标记年老代中的所有对象,这些对象是GC Roots,和年轻代中的某些活动对象引用的。

(2)并发标记,GC与应用程序线程并行运行,从初始标记中的根对象开始,遍历年老代所有活动对象进行标记。

(2)并行预清除,与应用线程同时运行,如果某些引用发生了变更,JVM会将变化的区域标记为脏区域。预清除阶段就是对这些脏区域进行处理,并标记还在存活的对象,然后空闲对象将被清除。预清除可以减少重标阶段的工作量。

(4)并发可中止预清除,该阶段也与应用线程并行,属于优化。增加这个阶段是为了让我们能控制该阶段结束的时间,也是为了减轻重标阶段的工作量。

# 控制参数
-XX:CMSScheduleRemarkEdenSizeThreshold=2M
-XX:CMSScheduleRemarkEdenPenetration=50
-XX:CMSMaxAbortablePrecleanTime=5000(单位为毫秒)

比如在并发预清理之后,如果年轻代占用高于CMSScheduleRemarkEdenSizeThreshold,则开始并发可中止的预清除并继续进行预清除,直到年轻代中达到CMSScheduleRemarkEdenPenetration百分比占用率,之后进入重标阶段。如果经过CMSMaxAbortablePrecleanTime时间仍然未达到要求,则直接进入重标阶段。

(5)重标阶段,触发STW,暂停所用应用线程。从GCroots 开始扫描标记年老代的所有活动对象。CMS会尝试在年轻代尽可能空的时候运行最后的备注阶段。

(6)并行清理,应用线程同时执行。该阶段的目的是删除未使用的对象,并回收它们占用的空间以备将来使用。

(7)并行复位,并发执行阶段,重置CMS算法的内部数据结构,并为下一个周期做好准备。

:如上CMS垃圾收集器进行大量工作为的是在年老代回收时不需要暂停应用线程,以减少暂停时间。但是,它存在一些缺点,其中最明显的是年老代碎片,并且在某些情况下,尤其是在大堆上,暂停持续时间缺乏可预测性。

3.5 G1 –垃圾优先

G1是Java9默认GC收集器。它设计的目标是应用在大内存的多处理器计算机,实现高吞吐量。一般应用堆应该在6GB以上且可预测的暂停时间低于0.5秒。G1作为并发标记扫描收集器(CMS)的替代产品。

G1堆内存与旧GC收集器堆内存管理完全不同。它将堆拆分为多个较小的区域(默认根据堆内存拆分为接近2048份)来存对象。

G1收集器的几个阶段:

(1)初始标记,触发STW,标记出从GC Roots直接访问的所有活动对象。

(2)并发标记,从已标记的对象开始扫描,并从根开始标记所有可访问的对象。这个阶段可以被年轻一代的垃圾收集打断。

(3)重新标记,因为并发标记与应用线程并行,所以可能存在遗漏的更新对象。此阶段触发STW,应用线程暂停,完成活动对象最后的标记。

(4)复制/清理阶段,G1选择“活度”最低的区域,这些区域可以被最快地收集。并发标记完成后将进行[GC pause (mixed)]混合GC,年轻代和年老代同时收集。

下图深绿色和深蓝色为清除压缩之后的区域。

G1中几个重要的参数:

# G1区域的大小。该值为2的幂,范围为1MB至32MB。目标是根据最小Java堆大小具有大约2048个区域。
-XX:G1HeapRegionSize=n

# 所需的最大暂停时间设置目标值。默认值为200毫秒。
-XX:MaxGCPauseMillis=200

# 设置要用作年轻代大小的最小值的堆百分比。默认值为Java堆的5%
-XX:G1NewSizePercent=5

# 设置堆大小的百分比,以用作年轻代大小的最大值。默认值为Java堆的60%。
-XX:G1MaxNewSizePercent=60

# 设置STW工作线程的值。将n的值设置为逻辑处理器的数量。的值与n逻辑处理器的数量相同,最多为8
# 如果逻辑处理器多于八个,则将的值设置为逻辑处理器的n大约5/8。在大多数情况下,这n是可行的,但大型SPARC系统的值可能约为逻辑处理器的5/16。
-XX:ParallelGCThreads=n

# 设置平行标记线的数量。设置n为并行垃圾回收线程数(ParallelGCThreads)的大约1/4 。
-XX:ConcGCThreads=n

# 设置触发标记周期的Java堆占用阈值。默认占用率为整个Java堆的45%。
-XX:InitiatingHeapOccupancyPercent=45

# 设置要包含在混合垃圾收集周期中的旧区域的占用阈值。默认占用率为65%。
-XX:G1MixedGCLiveThresholdPercent=65

# 当可回收百分比小于堆垃圾百分比时,Java HotSpot VM不会启动混合垃圾回收周期。默认值为10%。
-XX:G1HeapWastePercent=10

# 设置标记周期后混合垃圾回收的目标数量,以收集最多包含G1MixedGCLIveThresholdPercent实时数据的旧区域。默认值为8个混合垃圾回收。混合馆藏的目标是在此目标数量之内。
-XX:G1MixedGCCountTarget=8

# 设置在混合垃圾收集周期中要收集的旧区域数的上限。缺省值为Java堆的10%。
-XX:G1OldCSetRegionThresholdPercent=10

# 设置保留内存的百分比以使其保持空闲状态,以减少空间溢出的风险。默认值为10%。当增加或减少百分比时,请确保将总Java堆调整相同的数量。
-XX:G1ReservePercent=10

4、总结

本文记录GC算法基础和Java中的几种GC收集器。

到此这篇关于java中的GC收集器详情的文章就介绍到这了,更多相关java中的GC收集器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java 8如何自定义收集器(collector)详解

    需求: 将 一个容器List<Bean> 按照一定的字段进行分组,分组过后的值为特定的BEAN 里面的属性例如: 假定有这样一个Bean public class SubjectOberser{ private String subjectKey; private AbstractObserver abstractObserver; ...geter seter 方法... } 我们需要按照 subjectKey 进行分组,分组过后的内容 应该为这样一个容器Map<String,List

  • 使用jvisualvm配合Visual GC插件监控Java程序详细总结

    jvisualvm介绍 VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,它提供了运行监视.故障处理.性能分析(Profiling)等功能.VisuaIVM有一个很大的优点:不需要被监视的程序基于特殊Agent运 行,因此它对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境中. jdk8的文档中https://docs.oracle.com/javase/8/docs/technot

  • 解析Java内存分配和回收策略以及MinorGC、MajorGC、FullGC

    目录 对象内存分配与回收策略 对象何时进入新生代.老年代 三种GC介绍 MinorGC Major GC/Full GC: 图示GC过程 对象内存分配与回收策略 对象的内存分配,往大方向讲,就是在堆上分配[但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配),对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配.少数情况下也可能会直接分配在老年代中. 对象优先分配在Eden区,当Eden区可用空间不够时会进行MinorGC 大对象直接进入老年代:大对

  • Java SpringCache+Redis缓存数据详解

    目录 前言 一.什么是SpringCache 二.项目集成Spring Cache + Redis 1.配置方式 三.使用Spring Cache 四.SpringCache原理与不足 1.读模式 2.写模式:(缓存与数据库一致) 五.总结 前言 这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!! 这里就对自己学过来的内容进行一次的总结和归纳!!! 一.什么是SpringCache Spring Cache 是一个非常优秀的缓存组件.自

  • Java SpringBoot整合SpringCloud

    目录 1. SpringCloud特点 2. 分布式系统的三个指标CAP 3. Eureka 4. SpringCloud Demo 4.1 registry 4.2 api 4.3 provider 4.4 consumer 4.5 POSTMAN一下 1. SpringCloud特点 SpringCloud专注于为典型的用例和扩展机制提供良好的开箱即用体验,以涵盖其他情况: 分布式/版本化配置 服务注册和发现 Eureka 路由 Zuul 服务到服务的呼叫 负载均衡 Ribbon 断路器 H

  • Java8 Stream Collectors收集器使用方法解析

    Collectors.toMap: Student studentA = new Student("20190001","小明"); Student studentB = new Student("20190002","小红"); Student studentC = new Student("20190003","小丁"); //Function.identity() 获取这个对象本身

  • 浅谈JAVA8给我带了什么——流的概念和收集器

    到现在为止,笔者不敢给流下定义,从概念来讲他应该也是一种数据元素才是.可是在我们前面的代码例子中我们可以看到他更多的好像在表示他是一组处理数据的行为组合.这让笔者很难去理解他的定义.所以笔者不表态.各位同志自行理解吧. 在没有流以前,处理集合里面的数据一般都会用到显示的迭代器.用一下前面学生的例子吧.目标是获得学分大于5的前俩位同学. package com.aomi; import java.util.ArrayList; import java.util.Iterator; import j

  • JAVA垃圾收集器与内存分配策略详解

    引言 垃圾收集技术并不是Java语言首创的,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.垃圾收集技术需要考虑的三个问题是: 1.哪些内存需要回收 2.什么时候回收 3.如何回收 java内存运行时区域的分布,其中程序计数器,虚拟机栈,本地方法区都是随着线程而生,随线程而灭,所以这几个区域就不需要过多考虑回收问题.但是堆和方法区就不一样了,只有在程序运行期间我们才知道会创建哪些对象,这部分内存的分配和回收都是动态的.垃圾收集器所关注的就是这部分内存. 一 对象

  • 深入理解Java SpringCloud Ribbon 负载均衡

    目录 前言 1.抛出问题 2.源码解析 2.1.LoadBalancerIntercepor 2.2.LoadBalancerClient 2.3.负载均衡策略IRule 2.4.总结 3.负载均衡策略 总结 前言 该技术博客是关于黑马视频教程的笔记总结! 服务消费者需要通过RestTemplate调用注册中心(Eureka)的服务提供者,但当同一服务名称的服务有多个的时候,我们的服务消费者应该调用哪一个服务呢?这时候就需要我们学习理解Ribbon负载均衡的实现原理. 当我们在RestTempl

  • java中的GC收集器详情

    目录 1.GC(Garbage collection ) 2.GC算法 2.1标记活动对象 2.2 删除空闲对象 2.3 标记清除(Mark-Sweep) 2.4 清除压缩(Mark-Sweep-Compact) 2.5 标记和复制 3.JVM GC 3.1 JVM GC事件 3.2 Serial GC 3.3 Parallel GC 3.4 Concurrent Mark and Sweep 3.5 G1 –垃圾优先 4.总结 1.GC(Garbage collection ) 程序内存管理分

  • Java中JUC 的 Exchange 交换器详情

    目录 前言 基础使用 总结 前言 Exchange(交换器)顾名思义,它是用来实现两个线程间的数据交换的,它诞生于 JDK 1.5, 它有两个核心方法: exchange(V x):等待另一个线程到达此交换点,然后将对象传输给另一个线程,并从另一个线程中得到交换的对象.如果另一个线程未到达此交换点,那么此线程会一直休眠(除非遇了线程中断). exchange(V x, long timeout, TimeUnit unit):等待另一个线程到达此交换点,然后将对象传输给另一个线程,并从另一个线程

  • Java 流处理之收集器详解

    目录 收集所有记录的 列1 值,以列表形式存储结果 收集所有记录的 列1 值,且去重,以集合形式存储 收集记录的 列2 值和 列3 值的对应关系,以字典形式存储 收集所有记录中 列3 值最大的记录 收集所有记录中 列3 值的总和 创建一个中间结果容器 逐一遍历流中的每个元素,处理完成之后,添加到中间结果 中间结果转换成最终结果 combiner()是做什么的? characteristics()是什么的? 完整代码 Java 流(Stream)处理操作完成之后,我们可以收集这个流中的元素,使之汇

  • Java 中的类和对象详情

    目录 1.类的定义 2.类中变量的类型 3.构造方法 4.重载方法 5.继承 5.1 重写方法 6.创建对象 7.访问实例变量和方法 8.比较对象 8.1 使用 == 比较对象 8.2 使用 equals() 比较对象 类可以看成是创建Java对象的模板 1.类的定义 public class Dog { String name; int age; void eat() { } void sleep() { } } 2.类中变量的类型 局部变量:在方法或语句块中定义的变量被称为局部变量.变量声明

  • Java中的Spring循环依赖详情

    目录 什么是循环依赖? 那么循环依赖是个问题吗? Bean的生命周期 三级缓存 解决循环依赖思路分析 Spring到底解决了哪种情况下的循环依赖 总结 什么是循环依赖? 很简单,就是A对象依赖了B对象,B对象依赖了A对象. 比如: 那么循环依赖是个问题吗? 如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情. 比如: 这样,A,B就依赖上了. 但是,在Spring中循环依赖就是一个问题了,为什么? 因为,在Spring中,一个对象并不是简单new出来了,而是会经过一系

  • Java中线程上下文类加载器超详细讲解使用

    目录 一.什么是线程上下文类加载器 1.1.重要性 1.2.使用场景 二.ServiceLoader简单介绍 三.案例 3.1.使用ServiceLoader加载mysql驱动 3.2.Class.forName加载Mysql驱动 3.2.1.com.mysql.jdbc.Driver 3.2.2.java.sql.DriverManager初始化 3.2.3.调用DriverManager的registerDriver方法 3.2.4.执行DriverManager.getConnection

  • 浅析Java中的GC垃圾回收器的意义及与GC的交互

    对象是使用new创建的,但是并没有与之相对应的delete操作来回收对象占用的内存.当我们完成对某个对象的使用时,只需停止对该对象的引用:将我们的引用改变为指向其他对象或指向null;或者从方法中返回,使得该方法的局部变量不复存在,从而使得对这些局部变量的引用变为不指向任何对象.不再被引用的对象被称为垃圾(garbage),查找并回收这些对象的过程叫做垃圾回收(garbage collection) o Java虚拟机利用垃圾回收来保证被引用的对象将会在内存中保留,同时会释放在执行代码中通过任何

  • 全面解析Java中的GC与幽灵引用

    Java 中一共有 4 种类型的引用 : StrongReference. SoftReference. WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵), 这 4 种类型的引用与 GC 有着密切的关系,  让我们逐一来看它们的定义和使用场景 : 1. Strong ReferenceStrongReference 是 Java 的默认引用实现,  它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收 Java代码

  • Java中API的使用方法详情

    目录 1.API 1.1API概述 1.2API帮助文档的具体使用 2.String类 2.1String类概述 2.2String类的特点 2.3String类的构造方法 2.4创建字符串对象两种方式的区别 2.5字符串的比较 2.5.1==号的作用 2.5.2equals方法的作用 2.6用户登录案例 2.6.1案例需求 2.6.2代码实现 2.8 帮助文档查看String常用方法 3.StringBuilder类 3.1StringBuilder类概述 3.2StringBuilder类和

随机推荐