笔者最近在看关于G1垃圾收集器,发现了一篇十分优秀的文章,来自红帽(Red Hat)大佬。
笔者通过自己的理解后翻译后,有了本篇文章
本篇是Part 2:⭐⭐原文地址⭐⭐

欢迎回来!我希望您喜欢本系列的第 1 部分,我们深入了解了 G1 的工作原理并做出优化调整。在本系列的第二部分中,我们将深入探讨垃圾回收 (GC) 日志记录选项的广泛列表。为了确定可以应用优化的位置,您需要了解集合中涉及的不同步骤、这些步骤的含义以及它们对整体收集时间的影响。为此,我们将可用选项分为三个不同的类别,以查看日志的含义以及在什么情况下应该使用它们:

  1. 强制 - 如果没有这些设置,任何应用都不应在生产环境中运行。
  2. 高级 - 根据应用程序的成熟度和负载的增长率,这些是在需要额外调整时在生产中运行的注意事项。
  3. 调试 - 这些选项旨在解决特定问题或性能问题,除非无法在其他任何地方重现问题,否则不会在生产中使用。

这里的意思就相当于JVM日志(error,info,debug),对于每个java应用,如果被运行,都应该加上"强制"的配置后才能被运行–因为这些日志是必须的,如果出现了意外情况,可以帮助分析。

强制

从强制标志开始,这些选项提供了一种JVM GC 信息基线 :

JVM配置 描述
-Xloggc:/path/to/gc.log 写入 GC 日志的路径
-XX:+UseGCLogFileRotation 启用 GC 日志文件轮换
-XX:NumberOfGCLogFiles= 要保留的轮换 GC 日志文件数
-XX:GCLogFileSize= 用于启动轮换的每个 GC 日志文件的大小
-XX:+PrintGCDetails 详细的GC日志
-XX:+PrintGCDateStamps 实际日期和时间戳
-XX:+PrintGCApplicationStoppedTime 应用程序在 GC 期间停止的时间量
-XX:+PrintGCApplicationConcurrentTime 应用程序在 GC 之间运行的时间量
-XX:-PrintCommandLineFlags 打印 GC 日志中的所有命令行标志

作者给出的分析是,如果运行一个Java项目这些配置是必须的,能提供到后续分析所需日志;

在这些标志中,为日志文件数和每个日志文件的大小选择适当的值,确保维护适当的垃圾回收日志历史记录。我始终建议至少保留一周的日志,因为它为您提供了应用程序在给定一周内的性能信息。

PrintGCDetails

让我们更深入地了解通过“-XX:+PrintGCDetails”生成的日志的剖析,分为六个关键点:

  1. 第一点概述了四个关键信息:
    1.1 事件发生的实际日期和时间,通过设置“-XX:+打印GCDateStamps”-2016-12-12T10:40:18.811-0500记录
    1.2 自 JVM 启动开始到打印的相对时间戳 -29.959
    1.3 GC类型 - G1 疏散暂停(年轻代)- 将其标识为疏散暂停和年轻集合
    1.4 收集花费的时间 -0.0305171 秒

  2. 第二点概述了所有并行任务:
    2.1 Parallel Time并行时间-并行任务从收集开始时开始到最后一个 GC 工作程序结束时完成的 Stop The World (STW) 时间 - 26.6ms
    2.2 GC Worker-并行 GC 工作线程的数量,由 -XX:ParallelGCThreads -4 定义
    》2.2.1 默认为 CPU 数量,最多 8 个。对于 8+ CPU,它默认为 5/8 线程与 CPU 比率
    2.3 GC WorkerStart-自 GC 工作程序开始时 JVM 启动以来的最小/最大时间戳。差值表示第一个线程和最后一个线程开始之间的时间(以毫秒为单位)。理想情况下,您希望它们同时快速启动
    2.4 Ext Root Scanning-扫描外部根目录(线程堆栈根、JNI、全局变量、系统字典等)查找所花费的时间
    2.5 Update RS(记住集或 RSet)-每个区域都有自己的记忆集。它跟踪保存对某个区域的引用的卡片的地址。发生写入时,写后屏障通过将新引用的卡,标记为脏卡并放入日志缓冲区或脏卡队列来管理区域间引用中的更改。一旦填满,并发优化线程将并行处理这些队列,同时运行应用程序线程。更新 RS使 GC 工作程序能够处理在收集开始之前未处理的任何未处理缓冲区。这可确保每个 RSet 都是最新的
    》2.5.1 Process Buffer-这显示在更新 RS 期间处理了多少个更新缓冲区
    2.6 Scan RS-扫描每个区域的“记住的集”以查找指向收集组中区域的引用
    2.7 Code Root Scanning-扫描编译源代码的根目录以查找对收集组的引用所花费的时间
    2.8 Object Copy-在撤离暂停期间,必须清空收集组中的所有区域。对象复制负责将所有剩余的活动对象复制到新区域
    2.9 Termination-当 GC 工作线程完成时,它会进入一个终止例程,在该例程中,它与其他工作线程同步并尝试窃取未完成的任务。时间表示从工作人员首次尝试终止到实际终止所花费的时间
    》2.9.1 Termination Attempts-如果工作人员成功窃取了任务,它将重新进入终止例程并尝试窃取更多工作或终止。每次任务被盗并重新进入终止时,终止尝试的次数都会增加
    2.10 GC Worker Other-这表示在未计入先前任务的任务上花费的时间
    2.11 GC Worker Total-这显示了每个并行工作线程所花费时间的最小值、最大值、平均值、差异和总和
    2.12 GC Worker End-自 GC 工作程序结束时 JVM 启动以来的最小/最大时间戳。diff 表示第一个线程和最后一个线程结束之间的时间(以毫秒为单位)。理想情况下,您希望它们同时快速结束

  3. 第三点概述了串行任务:
    3.1 Code Root Fixup-指向 CSet 的行走标记方法,以修复在 GC 期间可能已移动的任何指针
    3.2 Code Root Perge-清除代码根表中的条目
    3.3 Clear CT-清除牌桌上的脏牌

  4. 第四点概述了以前没有考虑过的其他任务。它们也是串行的。
    4.1 Choose CSet -选择收集组的区域
    4.2 Ref Proc STW 引用处理器发现的任何软/弱/最终/幻像/JNI 引用
    4.3 Ref Enq 循环引用,并将其排队到挂起列表
    4.4 Redirt Cards 通过收集过程修改的卡片被标记为脏卡
    4.5 HumongousRegister 庞大的寄存器-启用“G1ReclaimDeadHumongousObjectsAtYoungGC”(JDK 8u60中添加默认为true/功能)后,G1将尝试在Young GC期间急切地收集Humongous区域。这表示评估巨型地区是否是渴望开垦的候选者并记录它们所花费的时间。有效的候选项将没有现有的强代码根,只有“记住集”中的稀疏条目。每个候选项都会将其记住的集刷新到脏卡队列中,如果清空,该区域将添加到当前收集组
    4.6 Humongous Recalim——确保巨大的对象已死亡并清理、释放区域、重置区域类型并将区域返回到可用列表并考虑释放空间所花费的时间
    4.7 Free Set -现在撤离的区域被添加回免费列表

第四部分基本上都是为下一次GC做准备

  1. 第五点概述了堆是如何变化的,以及他们因为GC后的大小调整:
    5.1 伊甸园: 1097.0M(1097.0M)->0.0B(967.0M)这说明当前年轻GC被触发是因为伊甸空间已满 - 分配的 1097.0M (1097.0M)它表明所有伊甸园区域都被疏散,使用量被收集减少到0.0B,这也表明,下一个GC的伊甸空间总分配已经减少到967.0M。
    幸存者:13.0M->139.0M,由于年轻的疏散,幸存者空间从13.0M增加到139.0M
    堆:1694.4M(2048.0M)->736.3M(2048.0M)在收集时,总体堆分配是最大值的 1694.4M (2048.0M)收集后,整体堆分配减少到 736.3M,最大堆保持不变,为 (2048.0M)

  2. 第六点表示收集所花费的时间:
    User=0.08:在收集期间,进程内用户代码中花费的 CPU 时间量。这说明了所有 CPU 上的所有线程。这不包括在流程之外花费的时间或等待所花费的时间。根据并行线程的数量,用户时间将比实时时间高很多
    系统=0.00:进程内内核中花费的 CPU 时间量。这说明了所有 CPU 上的所有线程。这不考虑在流程之外花费的时间或等待所花费的时间
    实际=0.03:这是从集合开始到结束的真实挂钟时间。这还包括在其他流程中花费的时间和等待所花费的时间

并发标记

您可能会遇到的下一个事件是并发标记。如第 1 部分所述,可以通过几种不同的方式触发并发标记,但它始终执行相同的工作。

  1. 第一点表示标记的开始:
    GC 暂停 (G1 疏散暂停) (年轻) (初始标记)
    为了利用 STW 暂停和跟踪所有可访问的对象,初始标记作为Young GC的一部分完成。初始标记设置两个top-at-mark-start (TAMS) 变量,以区分现有对象和并发标记期间分配的对象。TAMS 的任何对象都隐式被视为此周期的活动对象
  2. 第二点是第一个并发事件:
    2.1 GC 并发根区域扫描启动
    区域根扫描从初始标记中获取新的幸存者区域,并扫描它们以查找参考。从这些“根”区域找到的任何引用随后都会被标记
    2.2 GC 并发根区域扫描结束
  3. 第三点表示并发标记:
    3.1 GC 并发标记启动
    它与应用程序线程同时运行。默认情况下,并发线程数为并行线程数的 25%。它也可以通过 -XX:ConcGCThreads 显式设置。
    跟踪位图中所有活动对象的堆和标记。由于顶部 TAMS 上方的所有对象都是隐式活动的,因此我们只需要标记低于该阈值的对象
    考虑标记期间的并发更改。为了使 SATB(snapshot-at-the-beginning) 正常工作,它必须能够在拍摄初始快照时通过指针跟踪对象。为了实现这一点,预写屏障将原始值记录到 SATB 缓冲区,当该缓冲区已满时,该缓冲区将添加到由并发标记线程定期处理的全局列表中。
    实时数据核算与标记过程同时发生。每个区域的消耗空间被制成表格,为活动对象标记,以建立活跃度比
    3.2 GC 并发标记结束
  4. 第四点是STW阶段:
    GC 备注 / 最终标记 / GC引用处理 / 卸载
    此阶段是 STW,以便可以绘制最终图片。处理剩余的 SATB 缓冲区,并标记任何延迟的活动对象
  5. 第五点也是STW阶段-GC清理:
    完成最终活动对象计数。这是使用标准并行线程集按区域完成的
    它标记自初始标记以来分配的所有对象的卡片位图(TAMS 上方的所有对象)它还标记具有至少一个活动对象的任何区域的区域位图,在准备下一个标记时,将交换上一个位图和下一个位图
    具有零活动字节的死旧和巨大区域被释放和清除
    清理没有活动对象的区域的记忆集
    为了准备下一个周期,将根据旧区域的活动性对旧区域进行排序以进行收集组选择。
    从元空间中卸载死类
  6. 第六点再次是一个并行阶段:
    GC 并发清理启动
    它对步骤 5 中处理的空白区域执行最终清理
    清理每个区域的记住集:这包括稀疏和粗略的条目、来自卡缓存和代码根表
    当区域完全清理后,它们将添加到临时列表中。清理完成后,临时列表将合并到辅助空闲区域列表中,等待它们被添加回主空闲列表
    GC 并发清理结束

并发标记完成后,您将看到一个年轻 GC,紧跟一个混合 GC(这假设满足正确的标准,如第 1 部分所述)。正如您在下面的日志中看到的,“混合收藏”的任务与前面解释的年轻收藏相同。年轻GC和混合GC之间只有两个区别:
7. 第一点将此GC标识为混合。
GC暂停(G1 疏散暂停)(混合)
8. 收集组将包含通过并发标记确定的旧区域


您可能会遇到的第三种类型的集合,也是我们正在努力避免的集合类型,是完整 GC。在 G1 中,完整 GC 是单线程停止世界 (STW) 暂停,它将疏散和压缩所有区域。您可以从完整 GC 日志中获取三条重要信息。

  1. GC 原因(AllocationFailure)告诉您触发完整 GC 的原因。这将有助于您如何进行调优。另一个流行的原因是元数据 GC 阈值
  2. 它们发生的频率。如果每隔几天一次Full GC 那没关系,而每小时一次的Full GC 那就问题很大了
  3. Full GC 花费了多长时间。

我想触及的最后一个日志是从’-XX:+PrintGCApplicationStopTime’和’-XX:+PrintGCApplicationConcurrentTime’生成的。这些标志提供三个有用的数据点:

  1. 第一点告诉我们应用程序线程在安全点期间停止的时间量
  2. 第二点告诉我们将所有线程置于安全点并挂起它们所花费的时间
  3. 第三点告诉我们应用程序线程在安全点之间运行了多长时间

高级

转到高级标志,这些选项提供了对值和阈值的宝贵见解。

JVM指令 描述
-XX:+PrintAdaptiveSizePolicy 有关GC工程的详细信息
-XX:+PrintTenuringDistribution 幸存者空间的使用和分配
-XX:+PrintReferenceGC 处理引用所花费的时间

从“-XX:+PrintAdaptiveSizePolicy”开始,此标志将有关G1人体工程学的详细信息添加到前面讨论的每个事件中。这样可以深入了解收集组选择和暂停时间估计值。

查看年轻GC,原始详细日志中添加了五条新信息:

  1. 第一点告诉我们脏卡队列(CSet)中仍需要处理的卡数。它还提供了对处理需要多长时间的预测。预测包括更新 RS 和扫描 RS 的时间。
  2. 第二点告诉我们将包含在此集合中的区域数量。时间预测包括对象复制的估计值。
  3. 第三点提供了集合的最终CSet和时间预测。预测是基时间和年轻区域 CSet 时间的组合。
  4. 第四点是在某些情况下记录的,因此您可能只是偶尔看到它。如果您执行 GC 工作与应用程序工作所花费的时间大于特定阈值,G1 将尝试扩展堆。注意:如果最小/最大堆相同,则无法进行扩展。
  5. 仅当请求并发标记时,才会记录第五点。此日志围绕 GC 原因有一些变体,例如巨大的分配或标记是否尝试在它已经运行时启动。我们看到的最常见的形式是堆占用大于我们的 IHOP,因此开始标记。

紧跟在请求并发周期的年轻GC之后,您将看到GC工程的并行周期,带有年轻GC首字母young标记。这个年轻系列的其余细节保持不变。

标记完成后,您将看到一个 Young 系列,其中包含有关混合系列的符合人体工程学的日志。

  1. 第一点告诉我们,我们将开始混合GC,因为可回收百分比(22.62%)高于我们默认的G1HeapWastePercent(5%)。
    注意:如果可回收百分比低于 5%,您将看到类似的日志:不要启动混合 GC,原因:可回收百分比不超过阈值

现在混合集合将开始:

  1. 第一点,包括CSet的选择和年轻代的追加,与年轻GC相同。
  2. 第二点概述了添加到混合集合的 CSet 中的旧区域。在这种情况下,CSet 选择结束,因为达到了最大旧区域阈值。默认情况下,G1 最多只会将 10% 的旧区域添加到 CSet,由 -XX:G1OldCSetRegionThresholdPercent=X 定义。
  3. 第三点提供最终的CSet和暂停时间预测。
  4. 第四点为我们提供了有关混合GC状态的详细信息。在这种情况下,我们仍然可以收集 535 个旧区域,总计 305363768 字节或堆的 14.22%。鉴于这仍然高于我们的垃圾百分比,下一个系列将再次是混合的。

选择结束混合 GC:

  1. 此混合集合的第一点显示可回收百分比现已降至 5% 阈值以下,混合集合将不再继续。以下个出现的GC就Young了

  1. 第一点告诉我们,主可用列表或辅助空闲列表中没有空闲区域,因此,分配请求失败,并且已请求堆扩展。
  2. 第二个点记录扩展请求的数量。重要的是要注意,在第 1 点和第 2 点中,实际上还没有尝试过扩展。
  3. 第三点告诉我们,不会尝试堆扩展。当可用未提交区域数为 0 时,这会使扩展逻辑短路。由于分配失败,我们最终会执行完整的 GC。
  4. 第四点出现在最小堆小于最大堆的情况下。在这种情况下,G1 将尝试在完整 GC 后将堆缩小到 70%。
  5. 第五点告诉我们,堆正在缩小以及缩小了多少。

PrintTenuringDistribution 标志提供有关每个集合期间幸存者空间布局和阈值的信息。这很有用,因为它使您能够查看对象如何老化。

Tenuring Distribution数据向我们展示了幸存者空间的三个重要方面:

  1. 所需的幸存者大小,等于幸存者大小乘以目标幸存者比率(默认为 50%)
  2. 目标阈值,也称为对象可能保留的年龄或年轻 GC 的数量。这是通过将每个年龄中物体的大小相加,直到大小大于所需的幸存者大小来计算的
  3. 年龄分布,包括每个年龄的所有对象的大小以及幸存者空间使用量的增量总数

诊断

最后,我们有诊断和实验标志。这些标志可能会添加大量日志记录,应仅在必要时以及尝试调试特定问题时使用。

JVM产数 描述
-XX:+UnlockDiagnosticVMOptions 解锁诊断虚拟机操作系统
-XX:+G1SummarizeConcMark 汇总 JVM 出口处的并发标记
-XX:+G1PrintHeapRegions 打印为分配、清理、重用、压缩、cset、提交、失败等选择的堆区域…
-XX:+G1PrintRegionLivenessInfo 在每个并发标记周期之前和之后打印每个旧区域的上一个和下一个活动数据
-XX:+G1SummarizeRSetStats -XX:G1SummarizeRSetStatsPeriod=1 每 X 打印一次 RSet 处理信息,其中 X 以 GC 循环为单位进行测量
-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+LogVMOutput -XX:LogFile=/path/to/gc.log 打印有关安全点同步的原因和一些详细信息。可以控制打印前要收集的事件数。默认情况下,日志到 STDOut - LogVMOutput 可以将其推送到文件
-XX:+UnlockExperimentalVMOptions 解锁实验性VMOptions
-XX:G1LogLevel=fine, finer, finest 增加集合的日志记录详细程度
-XX:+G1TraceEagerReclaimHumongousObjects 在每次收集期间打印有关活体和死物的详细信息 巨大的物体
-XX:+G1ConcRegionFreeingVerbose 调试 JVM

‘-XX:+G1PrintHeapRegions’ 的输出增加了大量的日志记录。下图表示一组压缩的事件,用于说明可能发生的各种类型。某些事件发生在年轻GC下,而其他事件发生在完整GC期间


只有在尝试调试非常具体的问题(例如):

  • 调试撤离故障和故障区域数
  • 确定巨型物体的大小和频率
  • 跟踪和评估作为CSet的一部分分配和收集的伊甸园,幸存者和旧区域的数量
  1. Commit : 正在初始化或扩展堆,定义正在修改的区域的顶部和底部
  2. Alloc(Eden) :由底部地址定义的区域被分配为 Eden 区域
  3. CSet:为 CSET 选择的区域,将回收所有这些区域
  4. CleaUp :由底部地址定义的区域完全为空,并在并发标记期间清理
  5. UnCommit :完整 GC 后,如果堆收缩,您将看到一组未提交的区域
  6. ALLOC(Old):由底部地址定义的区域被分配为旧区域
  7. RETIRE:在集合结束时,最后分配的旧区域标记为已停用
  8. REUSE:在下一个 GC 开始时,以前停用的旧区域将重用为起点
  9. ALLOC(Survivor):由底部地址定义的区域被分配为幸存者区域
  10. EVAC-FAILURE:如果在收集期间发生撤出失败,此事件将概述每个失败的区域
  11. POST-COMPACTION(Old) :完整 GC 后,将为包含剩余实时数据的旧区域和巨型区域生成压缩后事件
  12. ALLOC(SingleH) :由底部和顶部地址定义的区域被分配为单个巨型区域,其中对象适合单个区域
  13. ALLOC(StartsH) : 由底部和顶部地址定义的区域被分配为“开始巨型”区域,其中对象足够大,可以跨越多个区域
  14. ALLOC(ContinuesH):由底部和顶部地址定义的区域被分配为连续巨型区域,其中这是跨越多个区域的对象的延续

‘-XX:+G1PrintRegionLivenessInfo’ 的输出也会产生许多额外的日志记录,但它仅限于并发标记周期的频率。如果要分析并发标记后以及排序后旧区域以提高效率以进行 CSet 选择,这将非常有用。

标记后输出(还可以包括 EDEN、FREE、SURV、HUMS 和 HUMC 区域类型)概述了上一个和下一个标记起点 (TAMS) 级别的详细区域细分,因为它与标记周期的对象活动性有关。输出中定义了八条信息:

  1. type:可以是旧的,伊甸园,幸存者,巨大的开始,巨大的继续和免费
  2. address-renge:区域的底部和结束值
  3. used:区域中已用字节总数,以区域底部和当前顶部之间的总数来衡量
  4. prev-live:从上一个标记周期的角度来看,实时字节数,测量为前一个 TAMS 与当前顶部之间的总和加上上一个标记周期中已知的活动对象(先前标记)
  5. next-live:从当前标记周期的角度来看,实时字节数,测量为下一个 TAMS 和当前顶部之间的总计加上当前标记周期中的已知活动对象(标记)
  6. gc-eff:这是通过将可回收字节(已知实时字节减去总区域容量)除以估计收集区域的时间(RS 扫描、对象复制和其他时间)来衡量的。效率越高,区域作为候选区域越好
  7. remset:区域记住集的大小,通过将区域表的大小与位图的大小乘以堆字大小来测量
  8. code-roots:区域为强代码根消耗的内存量(以字节为单位)。

“-XX:+G1SummarizeRSetStats”的详细程度可以通过设置“-XX:G1SummarizeRSetStatsPeriod=XX”来控制,该设置定义了摘要之间的GC周期数。在调试 RSet 特定问题(例如扫描和/或更新 RS 活动期间花费的时间过长)时,此设置非常有用。

此日志定义了数据的 3 个关键部分:

  1. 第一个与并发细化统计有关。在本例中,从 94 个缓冲区处理了 506 张卡,100% 的工作由并发线程完成。最后一块,粗化,告诉我们有多少 RSET 被粗化了。实质上,当多个区域引用一个区域中的对象时,您可能没有足够的空间来存储新的区域位图。在这种情况下,引用区域位图被标记为粗略。这很昂贵,因为必须扫描整个引用区域以查找传入的引用;
  2. 第二部分定义基于每个区域类型的总体记忆集统计信息
  3. 第三部分基于每个区域类型定义总体代码根集统计信息

对于标准集合,许多行项由多个基础任务组成。如果一个任务花费的时间比预期的长,您可以启用“-XX:G1LogLevel=finest”以提供每个操作的详细细分。此外,它还增加了每个工作人员在每项任务上花费的详细执行时间。

我们要触及的最后一个设置是’-XX:+G1TraceEagerReclaimHumongousObjects’。如果您遇到大量 Hugeous 分配,则可以启用此选项以提供有关收集器认为哪些 Giant 对象为“死”或“活”以快速回收的详细信息。在JDK8u60中引入了对巨型地区的快速开垦。

END

我希望这篇文章不仅能说明如何收集各种不同的 GC 日志,还能说明如何在整个调优和分析过程中解释和使用它们。我希望您继续关注本系列的下一篇文章,我们将深入研究各种选项,以收集和解释通过高级 GC 日志记录产生的大量数据。

看红帽巨佬解析⭐《二、G1垃圾回收配置解析》⭐相关推荐

  1. 看红帽巨佬解析⭐《一、G1垃圾回收期简介》⭐

    笔者最近在看关于G1垃圾收集器,发现了一篇十分优秀的文章,来自红帽(Red Hat)大佬. 笔者通过自己的理解后翻译后,有了本篇文章 本篇是Part 1:⭐⭐原文地址⭐⭐ 序 对于大多数人来说,Jav ...

  2. 万字长文教你看懂java G1垃圾回收日志

    文章目录 一.如何在idea打印G1日志 二.G1基础参数 三.G1新生代收集 1. 四个关键信息 2. 列出了新生代收集中并行收集的详细过程 3.列出了新生代GC中的一些任务: 4.包含一些扩展功能 ...

  3. 双/三色标记法的垃圾回收(GC)原理解析和缺陷解决方案(Go,Lua以及jvm的CMS和G1垃圾回收器中使用的回收算法)

    标记-清除算法 go和lua虚拟机以及jvm的CMS和G1垃圾回收器的回收算法的思想均来自于标记-清除算法(Mark-Sweep),它们的gc有重要的两部分: 1.从根节点遍历所有对象,如果可达到,则 ...

  4. 垃圾回收器之 G1 垃圾回收器

    4.4 G1 定义:Garbage First 2004论文发布 2009 JDK 6u14 体验 2012 JDK 7u4 官方支持 2019 JDK9 默认 (废弃了之前的 CMS 垃圾回收器) ...

  5. g1垃圾回收器与cms垃圾回收器详解及最佳实践

    2019独角兽企业重金招聘Python工程师标准>>> G1垃圾收集器入门 说明 concurrent: 并发, 多个线程协同做同一件事情(有状态) parallel: 并行, 多个 ...

  6. 和某ZYC巨佬和XXY巨佬的随机挑战2总结

    前言 一切的起点在那个炎热的酷暑,菜的一批的WYCWYCWYC坐在最容易被∗*∗的左下角.这时他永远都想不到,他与巨佬之间的挑战,即将开始. 正题 规则 随机跳333到蓝题,然后写完. 完成记录 题目 ...

  7. 和某ZYC巨佬的随机挑战1总结

    瞎搞事情经过 时间 忘了 地点 机房 人物 WYCWYCWYC蒟蒻和ZYCZYCZYC巨佬 起因 想瞎搞 经过 做题 结果 做完了 规则 luoguluoguluogu随机跳题,跳三道紫色题目来做.一 ...

  8. JVM面试必问:G1垃圾回收器

    摘要:G1垃圾回收器是一款主要面向服务端应用的垃圾收集器. 本文分享自华为云社区<JVM面试高频考点:由浅入深带你了解G1垃圾回收器!!!>,原文作者:Code皮皮虾 . G1垃圾回收器介 ...

  9. G1垃圾回收日志分析

    标准 gc 日志 使用G1垃圾回收器最难的地方是读懂回收日志.G1回收虽然也是分代的,但是打印出来的日志却不像其他回收器那样明显.所以需要好好配置JVM参数才行.先看下面一段日志,这段日志是通过配置好 ...

  10. 一文搞懂G1垃圾回收器

    G1是从JDK9之后的默认垃圾回收器,其功能强大,性能优异,不过目前市面的材料不算多,很多都是抄来抄去,讲得也不太清楚.经过仔细阅读oracle官网以及相关的材料,从整体上梳理了G1的过程,希望这一文 ...

最新文章

  1. “另一个程序正在使用此文件,进程无法访问”的解决方法
  2. linux文件中链接文件系统,一种基于Linux文件系统文件链接的缓存LRU方法
  3. 构建良好的敏捷团队氛围
  4. CodeForces - 858D Polycarp's phone book(字典树/map)
  5. 如何分析常见的TCP问题?
  6. js防篡改对象之不可扩展对象
  7. Apache+Mysql+php+ZenTaoPMS安装配置文档
  8. 未来码农或可以备份一个自己的大脑
  9. 将MNIST数据集转化为png文件
  10. 【代码优化】equals深入理解
  11. glide加载gif图不显示动画_Glide 加载gif的一些个人总结
  12. HTML学习的第三天
  13. SDP(Session Description Protocol)模型介绍(RFC3264)
  14. 【VUE】2、VUE-CREATE创建第一个VUE项目
  15. 学生动漫网页设计模板下载 火影忍者(7页)大学生HTML网页制作作品 简单漫画网页设计成品 dreamweaver学生网站模板...
  16. LeanStore论文分析
  17. RTSP、RTMP、HTTP协议
  18. 【AdvancedLocomotionSystemV】第七篇 C++ 实现角色蹲伏和跑步细节
  19. Ubuntu16.04下NVIDIA显卡驱动安装(华硕飞行堡垒7代,1660ti)
  20. SQL必知必会挑战题答案

热门文章

  1. Redis数据类型及编码
  2. outlook 您的组织策略阻止我们为您完成此操作 解决办法
  3. 高通平台msm8953 display子系统学习
  4. Pytorch之Optim(优化器)
  5. 如何使用电脑注册微博登陆模拟器
  6. 帅帅什么意思_帅帅帅是什么意思
  7. vue3.0引入element插件报错解决
  8. 一步一步理解欧拉公式
  9. 信息入口的新闻客户端如何盈利?
  10. 新手平面设计师如何在网上接单赚钱?