首页 > 免root版 > 怎么弄gg修改器的root_gg修改器怎么搞
怎么弄gg修改器的root_gg修改器怎么搞
  • 怎么弄gg修改器的root_gg修改器怎么搞

  • 大小:14.32MB日期:2024-04-24 10:41:45
  • 语言:简体中文系统:Android
绿色无毒,安全可靠!部分设备误报拦截请通过!

应用详情

大家好,今天小编为大家分享关于怎么弄gg修改器的root_gg修改器怎么搞的内容,赶快来一起来看看吧。

1. Garbage Collect(垃圾回收)

堆内存中有垃圾回收,比如Young区的Minor GC,Old区的Major GC,Young区和Old区的Full GC。
但是对于一个对象而言,怎么确定它是垃圾?是否需要被回收?怎样对它进行回收?等等这些问题我们还需要详细探索。
因为Java是自动做内存管理和垃圾回收的,如果不了解垃圾回收的各方面知识,一旦出现问题我们很难进行排查和解决,自动垃圾回收机制就是寻找Java堆中的对象,并对对象进行分类判别,寻找出正在使用的对象和已经不会使用的对象,然后把那些不会使用的对象从堆上清除。

1.1 如何确定一个对象是垃圾?

要想进行垃圾回收,得先知道什么样的对象是垃圾。

1.1.1 引用计数法(JVM一般不采取这种算法)

对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任何指针对其引用,它就是垃圾。
弊端 :如果AB相互持有引用,导致永远不能被回收。

1.1.2 可达性

所谓的可达性就是通过一系列称为“GC Root”的对象为起点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Root没有任何引用链相连(用图论的话来说,就是GC Root到这个对象不可达)时,则说明此对象是不可用的。

那么哪些对象可以作为GC Root呢?以Java为例,有以下几种:
1、虚拟机栈(栈帧中的本地变量表)中引用的对象。
2、方法区中的静态成员。
3、方法区中的常量引用的对象(全局变量)。
4、本地方法栈中JNI(一般说的Native方法)引用的对象。
注:第一和第四种都是指的方法的本地变量表,第三种主要指的是声明为final的常量值。
不可达对象一定被回收吗?
不一定。

1.2 什么时候会垃圾回收

GC是由JVM自动完成的,根据JVM系统环境而定,所以时机是不确定的。
当然,我们可以手动进行垃圾回收,比如调用System.gc()方法通知JVM进行一次垃圾回收,但是具体什么时刻运行也无法控制。也就是说System.gc()只是通知要回收,什么时候回收由JVM决定。但是不建议手动调用该方法,因为GC消耗的资源比较大。

(1)当Eden区或者S区不够用了
(2)老年代空间不够用了
(3)方法区空间不够用了
(4)System.gc()

1.3 读前须知

1.3.1 吞吐量

指一次性能测试过程中网络上传输的数据量的总和。

1.3.2 什么是Stop The World

等待所有用户线程进入安全点后并阻塞,做一些全局性操作的行为。
当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到“GC Roots”进行关系的组建,进而执行标记和清除。
在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于GC引起。

1.3.3 安全点

安全点是在程序执行期间的所有GC Root已知并且所有对对象的内容一致的点。

1.3.4 fork一个进程

fork是UNIX关于进程管理的一个术语,本质是新开一个进程,但是不从磁盘加载代码,而是从内存现有进程复制一份。
fork (函数) 计算机程序设计中的分叉函数。
返回值有两个:
①若成功调用一次则返回两个值,子进程返回0;
②父进程返回子进程标记。
否则,出错返回-1 。fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

1.3.5 GC算法的评判标准

1、吞吐量:即单位时间内的处理能力。
2、最大暂停时间:因执行GC而暂停执行程序所需的时间。
3、堆的使用效率:鱼与熊掌不可兼得,堆使用效率和吞吐量、最大暂停时间是不可能同时满足的。即可用的堆越大,GC运行越快;相反,想要利用有限的堆,GC花费的时间就越长。
4、访问的局部性:在存储器的层级构造中,我们知道越是高速存取的存储器容量会越小(具体可以参看我写的存储器那篇文章)。由于程序的局部性原理,将经常用到的数据放在堆中较近的位置,可以提高程序的运行效率。

2 垃圾收集算法

2.1 标记-清除算法(Mark-Sweep)

该算法分为标记和清除两个阶段。标记就是把所有活动对象都做上标记的阶段;清除就是将没有做上标记的对象进行回收的阶段。如下图所示。

优点

①实现简单
②与保守式GC算法兼容

缺点
标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

①碎片化:会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。在回收的过程中会产生被细化的分块,到后面,即使堆中分块的总大小够用,但是却因为分块太小而不能执行分配。
②分配速度:因为分块不是连续的,因此每次分块都要遍历空闲链表,找到足够大的分块,从而造成时间的浪费。所以标记和清除两个过程都比较耗时,效率不高。
③与写时复制技术不兼容:所谓写时复制就是fork的时候,内存空间只引用而不复制,只有当该进程的数据发生变化时,才会将数据复制到该进程的内存空间。这样,当两个进程中的内存数据相同的时候,就能节约大量的内存空间了。而对于标记-清除算法,它的每个对象都有一个标志位来表示它是否被标记,在每一次运行标记-清除算法的时候,被引用的对象都会进行标记操作,这个仅仅标记位的改变,也会变成对象数据的改变,从而引发写时复制的复制过程,与写时复制的初衷就背道而驰了。

2.2 为什么“GC标记-清除算法”与“写时复制技术(copy-on-write)”不兼容?

写时复制技术的优点是什么?
fork进程的时候,内存空间是引用而不是复制的。
意味着执行完fork后的两个进程的内存指向的是同一片区域。但是进程可能会执行不同的操作,产生不同的数据,这时候才在其他空闲内存区域写入一个新的对象并改写原指针。如果两个程序的大部分内存数据都是相同的,那么这个技术能省下非常多的内存空间。

而GC标记-清除算法做了什么?
“ …比如将在第 2 章中介绍的 GC 标记 – 清除算法,就是在对象的头部中设置 1 个 flag (标志位)来记录对象是否已标记,从而管理各个对象。… ”(书中原话)
在每一个执行 GC 的时候,标记清除算法都会对被引用的对象进行标记操作。被引用的对象仅仅意味着这个对象不是垃圾,不能被清除,而不表示对象的内容已经被改写了。

试想一种情况:
在fork后,两个程序都没有生成新的数据,也就是说所有对象的域都不变。
这时候执行一次 GC 标记-清除算法,标记阶段将所有被引用的对象的 flag 进行一个置位操作。这种操作的意义等同于改动了数据。这时候 “ 写时复制技术 ” 会判断对象已经被改动,从空闲内存中写入新的对象并改写原指针。
一次 GC 标记-清除算法 执行完以后,已经不存在共享的对象了,每一个对象都被复制了一遍。

2.3 标记-复制(Mark-Copying)

复制算法就是将内存空间按容量分成两块。当这一块内存用完的时候,就将还存活着的对象复制到另外一块上面,然后把已经使用过的这一块一次清理掉。这样使得每次都是对半块内存进行内存回收。内存分配时就不用考虑内存碎片等复杂情况,只要移动堆顶的指针,按顺序分配内存即可,实现简单,运行高效。

优点

①优秀的吞吐量。
②可实现高速分配:复制算法不用使用空闲链表。这是因为分块是连续的内存空间,因此,调用这个分块的大小,只需要这个分块大小不小于所申请的大小,移动指针进行分配即可。
③不会发生碎片化。
④与缓存兼容。

缺点

①堆的使用效率低下。
②不兼容保守式GC算法。
③递归调用函数。

2.3.1 复制算法为什么不适合老年代

复制收集算法在对象存活率较高时需要进行较多的复制操作,效率将会降低。更关键的是,如果不想浪费50%的内存空间,就需要提供额外的空间进行分配担保。由于老年代中对象存活率较高,而且找不到其他内存进行分配担保,所以老年代一般不能直接选用这种收集算法。

2.3.2 分配担保

一般情况下,复制算法将内存空间按照容量划分为两块(如上图所示),两块内存交替使用,当一块内存使用完的时候,就先将存活的对象逐一复制到另一块未使用的内存,然后将当前使用的这块内存一次性清理掉。极端情况下,对象全部存活,但是因为两块内存一样大,所以可以装得下。
为了提高内存利用率,有人提出了复制收集算法的改进方案(如下图所示),将内存空间按照8:1:1的比例划分为3块(比例可以调整),称较大的一块为Eden,较小的两块为Survivor,两个Survivor交替着配合Eden一起使用,每当需要进行垃圾回收,先将存活的对象复制到保留的Survivor,然后将Eden和之前使用的Survivor一起清理掉。由于Survivor的内存空间较小,极端情况下可能不够保存存活下来的对象,为了解决这个问题,需要提供一块额外的空间进行分配担保,把保存不下的对象存储到额外空间。

2.4 标记 – 整理(Mark-Compact)

根据老年代的特点,有人对“标记 – 清除”进行改进,提出了“标记 – 整理”算法。“标记 – 整理”算法的标记过程与“标记 – 清除”算法相同,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

其实上述过程相对”复制算法”来讲,少了一个”保留区”

2.5 分代收集算法(Generational Collection)

“分代收集”算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须用“标记-清理”或“标记-整理”算法来进行回收。

既然上面介绍了3种垃圾收集算法,那么在堆内存中到底用哪一个呢?

Young区:复制算法(对象在被分配之后,可能生命周期比较短,Young区复制效率比较高)。
Old区:标记清除或标记整理(Old区对象存活时间比较长,复制来复制去没必要,不如做个标记再清理)。

3 垃圾收集器

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

3.1 Serial

Serial收集器是最基本、发展历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯一选择。
它是一种单线程收集器,不仅仅意味着它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要的是其在进行垃圾收集的时候需要暂停其他线程。

优点:简单高效,拥有很高的单线程收集效率。
缺点:收集过程需要暂停所有线程。
算法:复制算法。
适用范围:新生代。

应用:Client模式下的默认新生代收集器。

3.2 Serial Old

Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器,不同的是采用”标记-整理算法”,运行过程和Serial收集器一样。

3.3 ParNew

可以把这个收集器理解为Serial收集器的多线程版本。

优点:在多CPU时,比Serial效率高。
缺点:收集过程暂停所有应用程序线程,但CPU时比Serial效率差。
算法:复制算法。
适用范围:新生代。
应用:运行在Server模式下的虚拟机中首选的新生代收集器。

3.4 Parallel Scavenge

①.Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器,看上去和ParNew一样,但是Parallel Scanvenge更关注系统的吞吐量。

②.特点:
Parallel Scavenge收集器的关注点与其他收集器不同, ParallelScavenge收集器的目标则是达到一个可控制的吞吐量(Throughput),(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),吞吐量优先,新生代并行多线程收集器,可以通过参数设置,采用复制算法。

吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)。
比如虚拟机总共运行了100分钟,垃圾收集时间用了1分钟,吞吐量=(100-1)/100=99%。
若吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序的运算任务。

③.使用场景:
主要适合在后台运算而不是太多交互的任务。比如需要与用户交互的程序,良好的响应速度能提升用户的体验;而高吞吐量则可以最高效率地利用CPU时间,尽快地完成程序的运算任务等。

④.重要参数:

3.5 Parallel Old

Parallel Old垃圾收集器是 Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法进行垃圾回收,也是更加关注系统的吞吐量。

3.6 CMS垃圾收集器

1.概述:CMS(Concurrent Mark Sweep)收集器,基于“标记-清除”算法实现的,作用于老年代的GC。

2.特点:相较于其他的垃圾收集器,CMS采用并发的方式,以获取最短回收停顿时间为目标,可用于对响应时间敏感的环境。

3.实现步骤

4.优点:

并发收集、低停顿

由于整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行的。

5.缺点:

6.解决:可以通过参数压缩调优。

3.7 G1垃圾收集器(Garbage-First)

使用G1收集器时,Java堆的内存布局与就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。
每个Region大小都是一样的,可以是1M到32M之间的数值,但是必须保证是2的n次幂,如果对象太大,一个Region放不下[超过Region大小的50%],那么就会直接放到H中。
设置Region大小:-XX:G1HeapRegionSize=M
所谓Garbage-Frist,其实就是优先回收垃圾最多的Region区域。

1.概述:面向服务端,分代收集可以独自管理Java堆,基于CMS收集器的缺点,G1收集器充分利用多CPU缩短STW的时间,甚至可控,并解决CMS的碎片问题。

2.特点:G1收集器的回收流程和CMS相似,相较于其他收集器,G1利用分而治之的思想将堆进行分区,划分为一个个的区域,达到解决碎片问题的目的。采用筛选回收的方式,减少STW的时间。

3.工作过程:

4.优点:

(1)分代收集(仍然保留了分代的概念)
(2)空间整合(整体上属于“标记-整理”算法,不会导致空间碎片)
(3)可预测的停顿(比CMS更先进的地方在于能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒)

5.分析:

6.使用场景(官网原文):

mended Use Cases for G1 The first focus of G1 is to provide a solution for users running applications that require large heaps with limited GC latency. This means heap sizes of around 6GB or larger, and stable and predictable pause time below 0.5 seconds. Applications running today with either the CMS or the ParallelOld garbage collector would benefit switching to G1 if the application has one or more of the following traits.

G1的第一个重点是为运行需要大量堆且GC延迟有限的应用程序的用户提供一个解决方案。这意味着堆大小约为6GB或更大,并且稳定且可预测的暂停时间低于0.5秒。
如果应用程序具有以下一个或多个特征,那么使用CMS或parallellold垃圾收集器运行的应用程序将有助于切换到G1。
超过50%的Java堆被实时数据占用。 对象分配率或提升率差异显著。 意外的长时间垃圾收集或压缩暂停(超过0.5到1秒)

3.8 ZGC

JDK11新引入的ZGC收集器,不管是物理上还是逻辑上,ZGC中已经不存在新老年代的概念了会分为一个个page,当进行GC操作时会对page进行压缩,因此没有碎片问题只能在64位的linux上使用,目前用得还比较少。

(1)可以达到10ms以内的停顿时间要求。
(2)支持TB级别的内存。
(3)堆内存变大后停顿时间还是在10ms以内。

3.9 垃圾收集器分类

串行收集器 → Serial和Serial Old :
只能有一个垃圾回收线程执行,用户线程暂停。 适用于内存比较小的嵌入式设备 。

并行收集器 [吞吐量优先] → Parallel Scanvenge、Parallel Old :
多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。 适用于科学计算、后台处理等弱交互场景 。

并发收集器[停顿时间优先] → CMS、G1 :
用户线程和垃圾收集线程同时执行(但并不一定是并行的,可能是交替执行的),垃圾收集线程在执行的时候不会停顿用户线程的运行。 适用于相对时间有要求的场景,比如Web 。

3.10 JDK默认垃圾收集器

jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.9 默认垃圾收集器G1
-XX:+PrintCommandLineFlagsjvm参数可查看默认设置收集器类型
-XX:+PrintGCDetails亦可通过打印的GC日志的新生代、老年代名称判断

查看方法:java -XX:+PrintFlagsInitial|grep UseConcMarkSweepGC

JDK 7+8

bool UseParallelGC := true {product}
UseParallelOldGC = true {product}

JDK9

bool UseG1GC = true {product}

4 常见问题

吞吐量和停顿时间

停顿时间 → 垃圾收集器进行垃圾回收终端应用执行响应的时间
吞吐量 → 运行用户代码时间/(运行用户代码时间+垃圾收集时间)

停顿时间越短就越适合需要和用户交互的程序,良好的响应速度能提升用户体验;
高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

小结:这两个指标也是评价垃圾回收器好处的标准。

4.1 如何选择合适的垃圾收集器

①.优先调整堆的大小让服务器自己来选择;
②.如果内存小于100M,使用串行收集器;
③.如果是单核,并且没有停顿时间要求,使用串行或JVM自己选;
④.如果允许停顿时间超过1秒,选择并行或JVM自己选;
⑤.如果响应时间最重要,并且不能超过1秒,使用并发收集器;

4.2 对于G1收集

JDK 7开始使用,JDK 8非常成熟,JDK 9默认的垃圾收集器,适用于新老生代。

是否使用G1收集器?
(1)50%以上的堆被存活对象占用。
(2)对象分配和晋升的速度变化非常大。
(3)垃圾回收时间比较长。

4.3 G1中的RSet

全称Remembered Set,记录维护Region中对象的引用关系。

试想,在G1垃圾收集器进行新生代的垃圾收集时,也就是Minor GC,假如该对象被老年代的Region中所引用,这时候新生代的该对象就不能被回收,怎么记录呢?
不妨这样,用一个类似于hash的结构,key记录region的地址,value表示引用该对象的集合,这样就能知道该对象被哪些老年代的对象所引用,从而不能回收。

4.4 如何开启需要的垃圾收集器

(1)串行
-XX:+UseSerialGC
-XX:+UseSerialOldGC
(2)并行(吞吐量优先):
-XX:+UseParallelGC
-XX:+UseParallelOldGC
(3)并发收集器(响应时间优先)
-XX:+UseConcMarkSweepGC
-XX:+UseG1GC

(本文中汇总收集了网络视频及网络资料,有补充的伙伴可以在评论区留言,感谢观看!)

以上就是关于怎么弄gg修改器的root_gg修改器怎么搞的全部内容,感谢大家的浏览观看,如果你喜欢本站的文章可以CTRL+D收藏哦。

相关文章

热门下载

大家还在搜