首页 > 免root版 > gg修改器免root防崩溃_Gg修改器免root
gg修改器免root防崩溃_Gg修改器免root
  • gg修改器免root防崩溃_Gg修改器免root

  • 大小:18.61MB日期:2024-4-19 13:21:11
  • 语言:简体中文系统:Android
无病毒 免积分 免充值

工具详情

各位游戏大佬大家好,今天小编为大家分享关于gg修改器免root防崩溃_Gg修改器免root的内容,轻松修改游戏数据,赶快来一起来看看吧。

有很多文章描述了一个拙劣的垃圾收集器是如何让应用程序濒临崩溃,不能满足承诺的服务等级协议(SLA)。例如,一段不可预测的漫长的垃圾收集停顿时间可能会轻易地超过其他高性能应用程序的响应时间要求。此外,当你使用一个非整理型的垃圾收集器(GC)时,就会增加堆内存的不规则性。例如,并发标记-清除(CMS)收集器会尝试通过一次串行的(也就是单线程的)完整垃圾收集(Full GC)来回收碎片化的堆内存,而这个过程会带来 STW(Stop The World)停顿时间。

现在,我们可以对以上段落进行扩展:假设年轻代发生了一次内存分配失败,那么便会触发一次年轻代垃圾收集,导致某些对象被晋升至老年代。更进一步地,假设碎片化的老年代没有足够的空间用来容纳最近晋升的对象。这种情况将会触发一次 Full GC 周期,此时便会整理堆内存。

当使用 CMS GC 时,Full GC 是串行的,并且会带来 STW 停顿时间。因此,在整个 Full GC 期间,你的应用程序线程将会停止运行,等待收集器完成堆内存空间的回收和整理工作。STW 停顿的持续时间取决于堆内存的大小和幸存对象的数量。

另外,即使你想要通过并行(也就是多线程的)整理来解决碎片化的问题,你仍然不能避免发生一次 Full GC(这个过程涉及 Java 堆内存的所有分代),而此时堆内存已经够用了,只需要从老年代回收一部分空闲空间即可。

当使用 Parallel Old 垃圾收集器时,这是一个常见的场景。使用 Parallel Old 来回收老年代的内存可能会带来 STW 停顿时间,在此期间会并行执行 Full GC。这种 Full GC 并不是增量的,它会带来一段漫长的 STW 停顿时间,不能和应用程序交错执行。

注意:你可以从此处获得更多关于 HotSpot 垃圾收集的信息。

在了解以上信息之后,我们将考虑一种名为“垃圾优先”(G1)收集器的解决方案,这是 HotSpot 最新的垃圾收集器(JDK 7u4 版本开始引入的)。

G1 垃圾收集器是一种增量型的收集器,具有并行整理内存碎片的功能。相比起 CMS 收集器和 Parallel Old 收集器,G1 收集器能够提供更加可预测的停顿时间。通过引入一个并行的、多阶段的并发标记周期,G1 收集器能够处理更大的堆内存,并且在最坏情况下还能够提供合理的停顿时间。使用 G1 收集器的基本思路就是设置你的堆内存范围(使用 -Xms
选项设置最小堆,使用 -Xmx 选项设置最大堆)和一个现实可行的(软实时)停顿时间目标(使用 -XX:MaxGCPauseMillis 选项),然后就让垃圾收集器自己完成工作。

传统的 GC 内存布局会将一块连续的 Java 堆内存分割成(连续的)年轻代和老年代。在引入 G1 收集器之后,HotSpot 便抛弃了这种内存布局方式。在 G1 收集器中,HotSpot 引入了“区域(Region)”的概念。一块大容量的连续的 Java 堆内存空间被分割成多个固定大小的堆内存区域。有一个“空闲”区域列表负责维护这些区域。随着需求的增加,空闲区域就会被分配给年轻代或老年代。这些区域的大小在 1MB 至 32MB 之间,取决于你的 Java 堆内存的总大小。我们的目标是将整个堆内存分割成大约 2048 个区域。某个区域一旦释放完成,它便会回到“空闲”区域列表之中。G1 收集器的原理就是尽可能多地(同时尽力满足停顿时间目标)回收 Java 堆内存,G1 会收集存活数据总量最少的区域,也就是优先收集垃圾最多的区域。因此,这种收集器才取名为“垃圾优先”垃圾收集器。

图-1:传统的 GC 内存布局

在使用 G1 收集器时,需要注意一件事情:不管年轻代,还是老年代,它们都不是连续的内存空间。这是一个非常方便的特性,因为现在可以更加动态地调整分代的大小。

自适应大小的 GC 算法,诸如 Parallel Old 收集器,最终会保留额外的内存空间,堆内存的每个年代可能需要用来适应其连续空间的约束。如果使用 CMS 收集器,那么就需要进行一次 Full GC,以便于调整 Java 堆内存和各个分代的大小。

相反,G1 收集器使用逻辑年代(年轻代和老年代是由非连续的区域集合组成的)的概念,这样就不会浪费太多的空间或时间。

可以肯定的是,G1 收集器的算法确实利用了 HotSpot 的某些基本概念。例如,内存分配的概念、将对象拷贝至 Survivor 区的概念,以及将对象晋升至老年代的概念,这些概念类似于 HotSpot 先前实现的垃圾收集器。Eden 区域和 Survivor 区域仍然能构成年轻代。除了为“巨型”对象分配内存之外,大多数对象都是在 Eden 区中分配内存的。(注意:对于 G1 收集器来说,如果对象体积大于等于区域容量的一半,那么这个对象就被称为“巨型对象”,应当直接在老年代的“巨型”区域中分配内存。)G1 收集器会根据你的停顿时间目标来选择一个自适应的年轻代大小。年轻代的大小可以在预设的最小值和预设的最大值之间,它和 Java 堆内存的大小存在函数关系。当 Eden 区达到容量时,G1 就会执行一次“年轻代垃圾收集”,此时便会带来一段“排空停顿时间”。在这段 STW 停顿时间之内,G1 会将存活对象从构成 Eden 区的区域之中拷贝(排空)至构成名为“to-space”的Survivor 区的区域之中。

图-2:垃圾优先收集器的内存布局

除此之外,根据对象的年龄和“老年化阈值”,G1 会将构成名为“from-space”的 Survivor 区的区域之中的存活对象拷贝至构成名为“to-space”的 Survivor 区的区域之中,或者晋升至构成老年代的区域之中。

每次年轻代垃圾收集都包含并行工作的时间,以及顺序/串行工作的时间。为了进一步说明这一点,本文将演示 G1 垃圾收集器的一段日志输出,采用 JDK 7u25 版本。

以下命令行选项会产生此后的 GC 日志输出:

java –Xmx1G –Xms1G –XX:+UseG1GC –XX:+PrintGCDetails –XX:+PrintGCTimeStamps GCTestBench

注意:本文使用默认的停顿时间,也就是 200ms。

0.189: [GC pause (young), 0.00080776 secs]

[Parallel Time: 0.4 ms]

[GC Worker Start (ms): 188.7 188.7 188.8 188.8

Avg: 188.8, Min: 188.7, Max: 188.8, Diff: 0.1]

[Ext Root Scanning (ms): 0.2 0.2 0.2 0.1

Avg: 0.2, Min: 0.1, Max: 0.2, Diff: 0.1]

[Update RS (ms): 0.0 0.0 0.0 0.0

Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0]

[Processed Buffers : 0 0 0 1

Sum: 1, Avg: 0, Min: 0, Max: 1, Diff: 1]

[Scan RS (ms): 0.0 0.0 0.0 0.0

Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0]

[Object Copy (ms): 0.2 0.2 0.1 0.2

Avg: 0.2, Min: 0.1, Max: 0.2, Diff: 0.0]

[Termination (ms): 0.0 0.0 0.0 0.0

Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0]

[Termination Attempts : 1 2 1 2

Sum: 6, Avg: 1, Min: 1, Max: 2, Diff: 1]

[GC Worker End (ms): 189.1 189.1 189.1 189.1

Avg: 189.1, Min: 189.1, Max: 189.1, Diff: 0.0]

[GC Worker (ms): 0.4 0.4 0.3 0.3

Avg: 0.4, Min: 0.3, Max: 0.4, Diff: 0.1]

[GC Worker Other (ms): 0.0 0.0 0.1 0.1

Avg: 0.1, Min: 0.0, Max: 0.1, Diff: 0.1]

[Clear CT: 0.2 ms]

[Other: 0.2 ms]

[Choose CSet: 0.0 ms]

[Ref Proc: 0.2 ms]

[Ref Enq: 0.0 ms]

[Free CSet: 0.0 ms]

日志缩进可以区分并行和顺序的工作分组。并行工作时间可以进一步分割成:

1. External Root Scanning

并行收集器的工作线程用于扫描外部根引用(例如:寄存器、线程栈等指向收集集合(CSet)的引用)所耗费的时间。

2. Update Remembered Sets (RSets)

RSet 可以帮助 G1 收集器追踪指向某个区域的引用。此处显示的时间是并行工作线程用于更新 RSet 所耗费的时间总量。

3. Processed Buffers

这个计数显示了工作线程处理了多少次“更新缓冲区”。

4. Scan RSets

这段时间用于扫描 RSet,查找指向某个区域的引用。这段时间的长度将取决于 RSet 数据结构的“粒度”。

5. Object Copy

在每次年轻代垃圾收集期间,收集器会将 Eden 区和名为“from-space”的 Survivor 区之中的所有存活对象拷贝至名为“to-space”的 Survivor 区或老年代之中。此处会列出工作线程完成这项任务所耗费的时间总量。

6. Termination

每个工作线程在完成它们的特定工作(例如:对象扫描和复制)之后,便会进入自己的“终止协议”。每个工作线程在终止运行之前会查找其他线程是否还有尚未完成的工作;如果有,那么就帮助其他线程完成工作;如果没有,那么就终止运行。此处列出的时间表示工作线程用于“终止协议”所耗费的时间。

7. Parallel worker ‘Other’ time

工作线程会执行一些其他的操作,这些操作没有被记入上述的任何一个并行操作之中,此处列出的就是这些操作耗费的时间。

顺序工作(每项工作都可以独立地并行化执行)可以被分割成:

1. Clear CT

垃圾收集器的工作线程用于清除扫描元数据的 RSet 的卡表(Card Table)所耗费的时间。

2. Other

一些其他工作所耗费的时间:

我们刚刚已经对很多概念有了初步的了解,例如:RSet、RSet粒度、更新缓冲区、CSet。在接下来的几个段落中,我们还会学习更多的概念,例如:初始快照(SATB)算法和屏障,等等。然而,为了更加深入地学习这些概念,我们就不得不深入研究 G1 收集器的内部原理,虽然这是一个很有趣的话题,但是超出了本文的范围。

现在,我们已经知道年轻代垃圾收集是如何开始填满老年代的,我们还需要引入(和理解)一个名为“标记阈值”的概念。当堆内存总量的占用率超过这个阈值时,G1 收集器将触发一次多阶段的并发标记周期。用来设置这个阈值的命令行选项是 –XX:InitiatingHeapOccupancyPercent ,它的默认值是 Java 堆内存总量的 45%。G1 收集器使用一种名为“初始快照(SATB)”的标记算法,它会在标记周期的“初始”阶段为堆内存中的存活对象集合创建一个逻辑快照。这种算法会使用写前屏障来记录和标记作为逻辑快照的组成部分的对象。现在,我们可以花费一些时间来讨论多阶段并发标记的各个阶段。首先,我们要查看 G1 收集器的日志输出:

0.078: [GC pause (young) (initial-mark), 0.00262460 secs]

[Parallel Time: 2.3 ms]

[GC Worker Start (ms): 78.1 78.2 78.2 78.2

Avg: 78.2, Min: 78.1, Max: 78.2, Diff: 0.1]

[Ext Root Scanning (ms): 0.2 0.1 0.2 0.1

Avg: 0.2, Min: 0.1, Max: 0.2, Diff: 0.1]

[Update RS (ms): 0.2 0.2 0.2 0.2

Avg: 0.2, Min: 0.2, Max: 0.2, Diff: 0.0]

[Processed Buffers : 2 3 2 2

Sum: 9, Avg: 2, Min: 2, Max: 3, Diff: 1]

[Scan RS (ms): 0.0 0.0 0.0 0.0

Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0]

[Object Copy (ms): 1.8 1.8 1.8 1.8

Avg: 1.8, Min: 1.8, Max: 1.8, Diff: 0.0]

[Termination (ms): 0.0 0.0 0.0 0.0

Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0]

[Termination Attempts : 1 1 1 1

Sum: 4, Avg: 1, Min: 1, Max: 1, Diff: 0]

[GC Worker End (ms): 80.4 80.4 80.4 80.4

Avg: 80.4, Min: 80.4, Max: 80.4, Diff: 0.0]

[GC Worker (ms): 2.2 2.2 2.2 2.2

Avg: 2.2, Min: 2.2, Max: 2.2, Diff: 0.1]

[GC Worker Other (ms): 0.0 0.1 0.1 0.1

Avg: 0.1, Min: 0.0, Max: 0.1, Diff: 0.1]

[Clear CT: 0.2 ms]

[Other: 0.2 ms]

[Choose CSet: 0.0 ms]

[Ref Proc: 0.1 ms]

[Ref Enq: 0.0 ms]

[Free CSet: 0.0 ms]

[Eden: 3072K(5120K)->0B(5120K) Survivors: 1024K->1024K Heap: 16M(32M)->16M(32M)]

[Times: user=0.06 sys=0.00, real=0.00 secs]

0.081: [GC concurrent-root-region-scan-start]

0.082: [GC concurrent-root-region-scan-end, 0.0009122]

0.082: [GC concurrent-mark-start]

<snip> [Zero or more embedded young garbage collections are possible here,

but removed for brevity.]

0.094: [GC concurrent-mark-end, 0.0115579 sec]

0.094: [GC remark 0.094: [GC ref-proc, 0.0000033 secs], 0.0004374 secs]

[Times: user=0.00 sys=0.00, real=0.00 secs]

0.094: [GC cleanup 22M->10M(32M), 0.0003031 secs]

[Times: user=0.00 sys=0.00, real=0.00 secs]

0.095: [GC concurrent-cleanup-start]

0.095: [GC concurrent-cleanup-end, 0.0000350]

另外,每个阶段的解释,如下所述:

一旦 G1 收集器成功地完成并发标记周期,它就具备启动老年代垃圾收集所需要的相关信息。直到现在,还是不能对老年代的区域进行垃圾收集,因为 G1 收集器尚不具备任何与这些区域相关联的标记信息。由于 G1 收集器不仅对 Eden 区和 Survivor 区的区域进行垃圾收集,而且还会(可选地)添加老年代的区域进行混合垃圾收集,这种垃圾收集方式有助于老年代的碎片整理和区域排空,因此被恰当地称为“混合”垃圾收集。现在,我们将讨论一些重要的细节,以便于理解混合垃圾收集。

混合垃圾收集通常是由多个混合垃圾收集周期组成。当收集了足够数量的老年代区域时,G1 收集器会再次执行年轻代垃圾收集,直至下一次标记周期完成。有一些命令行选项能够控制添加至 CSet 的老年代区域的精确数量,如下所示:

我们可以看一下 G1 收集器的混合垃圾收集周期的日志输出:

1.269: [GC pause (mixed), 0.00373874 secs]

[Parallel Time: 3.0 ms]

[GC Worker Start (ms): 1268.9 1268.9 1268.9 1268.9

Avg: 1268.9, Min: 1268.9, Max: 1268.9, Diff: 0.0]

[Ext Root Scanning (ms): 0.2 0.2 0.2 0.1

Avg: 0.2, Min: 0.1, Max: 0.2, Diff: 0.1]

[Update RS (ms): 0.0 0.0 0.0 0.0

Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0]

[Processed Buffers : 0 0 0 1

Sum: 1, Avg: 0, Min: 0, Max: 1, Diff: 1]

[Scan RS (ms): 0.1 0.0 0.0 0.1

Avg: 0.1, Min: 0.0, Max: 0.1, Diff: 0.1]

[Object Copy (ms): 2.6 2.7 2.7 2.6

Avg: 2.7, Min: 2.6, Max: 2.7, Diff: 0.1]

[Termination (ms): 0.1 0.1 0.0 0.1

Avg: 0.0, Min: 0.0, Max: 0.1, Diff: 0.1]

[Termination Attempts : 2 1 2 2

Sum: 7, Avg: 1, Min: 1, Max: 2, Diff: 1]

[GC Worker End (ms): 1271.9 1271.9 1271.9 1271.9

Avg: 1271.9, Min: 1271.9, Max: 1271.9, Diff: 0.0]

[GC Worker (ms): 3.0 3.0 3.0 2.9

Avg: 3.0, Min: 2.9, Max: 3.0, Diff: 0.0]

[GC Worker Other (ms): 0.1 0.1 0.1 0.1

Avg: 0.1, Min: 0.1, Max: 0.1, Diff: 0.0]

[Clear CT: 0.1 ms]

[Other: 0.6 ms]

[Choose CSet: 0.0 ms]

[Ref Proc: 0.1 ms]

[Ref Enq: 0.0 ms]

[Free CSet: 0.3 ms]

总而言之,通过引入构成逻辑分代的区域(Region)的概念,G1 收集器的性能要优于先前的垃圾收集器。G1 收集器可以对老年代进行增量收集,而区域能够提供更细的粒度。G1 通过复制存活数据来完成绝大部分的回收工作,从而实现了内存碎片整理。相对于不具备碎片整理功能的空间回收技术来说,这种方式明显迈进了一大步,使得老年代看起来就像是瑞士奶酪一样!

在(多阶段标记周期的)清理阶段期间,会发生第一级内存回收,此时 G1 收集器将回收能够完全释放(例如:充满垃圾)的区域,然后将这些区域返回至空闲列表之中。在增量的混合垃圾收集期间,会发生下一级内存回收。如果两级回收都失败了,那么就会对整个 Java 堆内存进行垃圾收集。这就是众所周知的完整垃圾收集(Full GC),这是收集器的一种安全失败(Fail-Safe)机制。

上述的所有措施大大简化了老年代的内存回收,使得 G1 能够以一种分层的方式进行垃圾收集。

我希望这篇文章有助于读者初步了解 G1 收集器的不同之处和基本构成。感谢您的阅读!

以上就是关于gg修改器免root防崩溃_Gg修改器免root的全部内容,游戏大佬们学会了吗?

技能推荐

热门下载

其他人还在搜