热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【译】Java垃圾回收算法[截止到Java9]

原文:"JavaGarbageCollectionAlgorithms[tillJava9]"垃圾回收(Garbagecollection,

【译】Java垃圾回收算法[截止到Java 9]

原文:Java Garbage Collection Algorithms [till Java 9]

垃圾回收(Garbage collection,GC)一直是 Java 流行背后的重要特性之一。垃圾回收是 Java 中用于释放未使用内存的机制。本质上,它跟踪所有仍在使用的对象,并将其余的标记为垃圾。Java 的垃圾收集被认为是一种自动内存管理模式,因为程序员不必将对象指定为准备释放的对象。垃圾回收在低优先级线程上运行。

目录:

  • 对象生命周期(Object Life Cycle)
  • 垃圾回收算法(Garbage collection algorithms)
    • 标记清除(Mark and sweep)
    • 并发标记清除垃圾回收(Concurrent mark sweep (CMS) garbage collection)
    • 串行收集器(Serial garbage collection)
    • 并行收集器(Parallel garbage collection)
    • G1(垃圾优先)收集器(G1 garbage collection)
  • GC自定义选项
    • GC配置标记
    • GC日志标记
  • 总结

对象生命周期(Object Life Cycle)

Java 的对象生命周期可以分为3个阶段:

  1. 对象创建(Object creation),如使用关键字new。
  2. 使用中的对象(Object in use)
  3. 对象销毁(Object destruction)

垃圾回收算法(Garbage collection algorithms)

标记清除(Mark and sweep)

它是初始的和非常基本的算法,分两个阶段运行:

  1. 标记存活对象(Marking live objects)– 找出所有仍然活着的对象
  2. 删除不可到达的对象(Removing unreachable objects)

首先,GC 将一些特定的对象定义为垃圾收集根(Garbage Collection Roots)。 例如,当前执行方法的局部变量和输入参数、活动线程、加载类的静态字段和 JNI 引用。现在,GC 遍历内存中的整个对象图,从这些根开始,然后从根引用到其他对象。 GC访问的每个对象都被标记为活动的。

第二阶段是清除未使用的对象以释放内存。这可以通过多种方式来实现,例如:

  • 常规删除(Normal deletion)- 常规删除会删除未引用的对象以释放空间,并留下引用的对象和指针。 内存分配器(类似于散列表)保存对可以分配新对象的空闲空间块的引用。 它通常被称为标记-清除(mark-sweep)算法。

  • 删除-压缩(Deletion with compacting)- 只删除未使用的对象是没有效率的,因为空闲内存块分散在存储区域中,如果创建的对象足够大并且没有找到足够大的内存块,就会导致 OutOfMemoryError 错误。 为了解决这个问题,在删除未引用的对象之后,将对剩余的引用对象进行压缩。 这里的压缩指的是将被引用的对象移动到一起的过程。 这使得新的内存分配更加容易和快速。它通常被称为标记-清除-压缩(mark-sweep-compact)算法。

  • 复制删除(Deletion with copying)- 与标记和压缩的方法非常类似,因为他们也重新安置所有存活对象。 重要的区别在于迁移的目标是不同的内存区域。它通常被称为标记-复制(mark-copy)算法。

并发标记清除垃圾回收(Concurrent mark sweep (CMS) garbage collection)

它试图通过与应用程序线程并发执行大部分垃圾收集工作来最小化垃圾收集引起的暂停。 该算法在年轻代中采用并行stop-the-world标记复制(mark-copy)算法,在老年代中采用大多并发的标记清除(mark-sweep)算法。

由于从JDK9开始CMS被标记为废弃,并且在JDK14中完全移除,因此不再介绍该收集器。

串行收集器(Serial garbage collection)

该算法对年轻代使用标记-复制(mark-copy),对老年代使用标记-清除-压缩(mark-sweep-compact)。它在单线程上工作。在执行时,它会冻结所有其他线程,直到垃圾回收操作结束。

由于串行垃圾收集具有线程冻结(thread-freezing)的特性,因此只适用于非常小的程序。

要使用 Serial GC,请使用以下 JVM 参数:

-XX:+UseSerialGC

并行收集器(Parallel garbage collection)

类似于串行GC,年轻代使用标记-复制(mark-copy),老年代使用标记-清除-压缩(mark-sweep-compact)。多个并发线程用于标记和复制/压缩阶段。可以使用 -XX:ParallelGCThreads=N 选项配置线程数。

并行垃圾收集器适用于主要目标是通过有效利用现有系统资源来提高吞吐量的多核机器上。使用这种方法,可以大大减少GC的周期时间。

直到Java 8,并行收集器是默认的垃圾收集器。从 Java 9开始,G1是32位和64位服务器配置的默认垃圾收集器。

要使用并行 GC,请使用以下 JVM 参数:

-XX:+UseParallelGC

G1(垃圾优先)收集器(G1 garbage collection)

G1(Garbage First)垃圾收集器在Java 7中可用,被设计为CMS收集器的长期替代品。 G1收集器是一个并行、并发和增量压缩的低暂停垃圾收集器。

这种方法包括将内存堆分割成多个小区域(通常是2048)。每个地区被标记为年轻代(进一步分为伊甸园区域或幸存者区域)或老年代。这使得GC可以避免立即回收整个堆,而是以增量方式处理问题。这意味着一次只考虑区域的一个子集。

G1持续跟踪每个区域包含的存活数据量。此信息用于确定包含最多垃圾的区域; 因此它们首先被回收。这就是为什么它被命名为垃圾优先收集。

与其他算法一样,不幸的是,压缩操作使用 Stop the World 方法进行。但是根据它的设计目标,你可以为它设定具体的性能目标。您可以配置暂停时间,例如,在任何给定的时间内,暂停时间不超过10毫秒。G1收集器将尽最大努力以高概率实现这一目标(但不是确定性的,由于操作系统级别的线程管理,这将是实时性的困难)。

如果你想在 Java 7 或 Java 8 机器上使用,请使用如下的 JVM 参数:

-XX:+UseG1GC

G1自定义选项

标记
描述
-XX:G1HeapRegiOnSize=16m 堆区域的大小。该值的大小为2的幂,范围从1MB到32MB。我们的目标是根据最小的Java 堆大小设置大约2048个区域
-XX:MaxGCPauseMillis=200 为期望的最大暂停时间设置目标值。默认值是200毫秒。指定的值不适合堆大小
-XX:G1ReservePercent=5 这决定了堆中的最小储备
-XX:G1COnfidencePercent=75 这是信心系数暂停预测启发式
-XX:GCPauseIntervalMillis=200 这是每个MMU的暂停间隔时间片(以毫秒为单位)

GC自定义选项

GC配置标记

标记
描述
-Xms2048m -Xmx3g 设置初始和最大堆大小(年轻代+老年代)
-XX:+DisableExplicitGC 这将导致JVM忽略应用程序对System.gc()方法的任何调用。
-XX:+UseGCOverheadLimit This is the use policy used to limit the time spent in garbage collection before an OutOfMemory error is thrown.
-XX:GCTimeLimit=95 This limits the proportion of time spent in garbage collection before an OutOfMemory error is thrown. This is used with GCHeapFreeLimit.
-XX:GCHeapFreeLimit=5 This sets the minimum percentage of free space after a full garbage collection before an OutOfMemory error is thrown. This is used with GCTimeLimit.
-XX:InitialHeapSize=3g 设置初始堆空间(年轻区+老年区)
-XX:MaxHeapSize=3g 设置最大堆空间(年轻区+老年区)
-XX:NewSize=128m 设置年轻区的初始空间
-XX:MaxNewSize=128m 设置年轻区的最大空间
-XX:SurvivorRatio=15 设置单个幸存者空间的大小为伊甸园空间大小的一部分
-XX:PermSize=512m 设置永久区的初始空间
-XX:MaxPermSize=512m 设置永久区的最大空间
-Xss512k 设置专用于每个线程的栈区域的大小(以字节为单位)

GC日志标记

标记
描述
-verbose:gc or -XX:+PrintGC This prints the basic garbage collection information.
-XX:+PrintGCDetails This will print more detailed garbage collection information.
-XX:+PrintGCTimeStamps You can print timestamps for each garbage collection event. The seconds are sequential and begin from the JVM start time.
-XX:+PrintGCDateStamps You can print date stamps for each garbage collection event.
-Xloggc: Using this you can redirect garbage collection output to a file instead of the console.
-XX:+PrintTenuringDistribution You can print detailed information regarding young space following each collection cycle.
-XX:+PrintTLAB You can use this flag to print TLAB allocation statistics.
-XX:+PrintReferenceGC Using this flag, you can print the times for reference processing (that is, weak, soft, and so on) during stop-the-world pauses.
-XX:+HeapDumpOnOutOfMemoryError This creates a heap dump file in an out-of-memory condition.

总结
  • 对象生命周期分成3个阶段,对象创建,对象使用和对象销毁。
  • 标记-清除、标记-清除-压缩、标记-复制机制如何工作。
  • 不同的单线程和并发垃圾回收算法。
  • 直到Java 8, 并发收集器是默认算法。
  • 从Java 9开始, G1是默认算法。
  • 此外,还有各种标志,用于控制垃圾收集算法的行为并记录任何应用程序的有用信息


推荐阅读
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 关于CMS收集器的知识介绍和优缺点分析
    本文介绍了CMS收集器的概念、运行过程和优缺点,并解释了垃圾回收器的作用和实践。CMS收集器是一种基于标记-清除算法的垃圾回收器,适用于互联网站和B/S系统等对响应速度和停顿时间有较高要求的应用。同时,还提供了其他垃圾回收器的参考资料。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • MySQL中的MVVC多版本并发控制机制的应用及实现
    本文介绍了MySQL中MVCC的应用及实现机制。MVCC是一种提高并发性能的技术,通过对事务内读取的内存进行处理,避免写操作堵塞读操作的并发问题。与其他数据库系统的MVCC实现机制不尽相同,MySQL的MVCC是在undolog中实现的。通过undolog可以找回数据的历史版本,提供给用户读取或在回滚时覆盖数据页上的数据。MySQL的大多数事务型存储引擎都实现了MVCC,但各自的实现机制有所不同。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 本文介绍了Java集合库的使用方法,包括如何方便地重复使用集合以及下溯造型的应用。通过使用集合库,可以方便地取用各种集合,并将其插入到自己的程序中。为了使集合能够重复使用,Java提供了一种通用类型,即Object类型。通过添加指向集合的对象句柄,可以实现对集合的重复使用。然而,由于集合只能容纳Object类型,当向集合中添加对象句柄时,会丢失其身份或标识信息。为了恢复其本来面貌,可以使用下溯造型。本文还介绍了Java 1.2集合库的特点和优势。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • VSCode快速查看函数定义和代码追踪方法详解
    本文详细介绍了在VSCode中快速查看函数定义和代码追踪的方法,包括跳转到定义位置的三种方式和返回跳转前的位置的快捷键。同时,还介绍了代码追踪插件的使用以及对符号跳转的不足之处。文章指出,直接跳转到定义和实现的位置对于程序员来说非常重要,但需要语言本身的支持。以TypeScript为例,按下F12即可跳转到函数的定义处。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 玩转直播系列之消息模块演进(3)
    一、背景即时消息(IM)系统是直播系统重要的组成部分,一个稳定的,有容错的,灵活的,支持高并发的消息模块是影响直播系统用户体验的重要因素。IM长连接服务在直播系统有发挥着举足轻重的 ... [详细]
  • Python中程序员的面试题有哪些
    小编给大家分享一下Python中程序员的面试题有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有 ... [详细]
  • Java使用poi 5.0解析Excel工作簿的例子
    写在之前Excel文档是日常办公中非常普遍的一种数据记录模式。在业务场景中,往往有“导入Excel到某某系统中”的需求,所以这里记录一种使用poi5.0系 ... [详细]
author-avatar
食品质量的安全
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有