热门标签 | 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是默认算法。
  • 此外,还有各种标志,用于控制垃圾收集算法的行为并记录任何应用程序的有用信息


推荐阅读
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
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社区 版权所有