「Java设置ZGC」java设置excel单元格格式

博主:adminadmin 2023-01-01 21:42:09 911

今天给各位分享Java设置ZGC的知识,其中也会对java设置excel单元格格式进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

6个重要的JVM性能参数

围绕垃圾收集和内存,您可以将600多个参数传递给 JVM 。如果包括其他方面,则JVM参数总数将很容易超过1000+。任何人都无法消化和理解太多的论据。在本文中,重点介绍了七个重要的 JVM 参数,在 Java性能测试 中起着非常重要的作用。

-Xmx 可能是最重要的 JVM 参数。 -Xmx 定义要分配给应用程序的最大堆大小。。您可以这样定义应用程序的堆大小: -Xmx2g 。

堆大小在影响应用性能和所需物理硬件需求。这带来了一个问题,我的应用程序正确的堆大小是多少?我应该为应用程序分配大堆大小还是小堆大小?答案是:取决于需求和预算。

将 -Xms 和 -Xmx 设置为相同值的会提高JVM性能

元空间是将存储 JVM 的元数据定义(例如类定义,方法定义)的区域。默认情况下,可用于存储此元数据信息的内存量是无限的(即受您的容器或计算机的RAM大小的限制)。您需要使用 -XX:MaxMetaspaceSize 参数来指定可用于存储元数据信息的内存量的上限。

-XX:MaxMetaspaceSize=256m

OpenJDK中有7种不同的GC算法:

如果您未明确指定GC算法,那么JVM将选择默认算法。在Java 8之前, Parallel GC 是默认的GC算法。从Java 9开始, G1 GC 是默认的GC算法。

GC算法的选择对于确定应用程序的性能起着至关重要的作用。根据我们的研究,我们正在使用Z GC算法观察到出色的性能结果。如果使用 JVM 11+ ,则可以考虑使用 Z GC 算法(即 -XX:+ UseZGC )。

下表总结了激活每种垃圾收集算法所需传递的JVM参数。

垃圾收集日志包含有关垃圾收集事件,回收的内存,暂停时间段等信息,可以通过传递以下JVM参数来启用垃圾收集日志:

从JDK 1到JDK 8:

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:{file-path}

从JDK 9及更高版本开始:

-Xlog:gc*:file={file-path}

Demo:

通常,GC日志用于调整垃圾回收性能。但是,GC日志包含重要的微观指标。这些指标可用于预测应用程序的可用性和性能特征。在本文中将重点介绍一种这样的标尺:GC吞吐量。GC吞吐量是您的应用程序在处理客户交易中花费的时间与它在处理GC活动中花费的时间之比。假设您的应用程序的GC吞吐量为98%,则意味着应用程序将其98%的时间用于处理客户活动,其余2%用于GC活动。

现在,让我们看一个健康的JVM的堆使用情况图:

您会看到一个完美的锯齿图案。您会注意到,当运行Full GC(红色三角形)时,内存利用率将一直下降到最低。

现在,让我们看一下有问题的JVM的堆使用情况图:

您可以注意到,在图表的右端,即使GC反复运行,内存利用率也没有下降。这是一个典型的内存泄漏迹象,表明该应用程序正在存在某种内存问题。

如果您仔细观察一下该图,您会发现重复的完整GC开始在上午8点左右开始。但是,该应用程序仅在上午8:45左右开始获取OutOfMemoryError。到上午8点,该应用程序的GC吞吐量约为99%。但是,在上午8点之后,GC吞吐量开始下降到60%。因为当重复的GC运行时,该应用程序将不会处理任何客户交易,而只会进行GC活动。

OutOfMemoryError 是一个严重的问题,它将影响您的应用程序的可用性和性能。要诊断 OutOfMemoryError 或任何与内存相关的问题,必须在应用程序开始遇到 OutOfMemoryError 的那一刻或一瞬间捕获堆转储。由于我们不知道何时会抛出 OutOfMemoryError ,因此很难在抛出时左右的正确时间手动捕获堆转储。但是,可以通过传递以下JVM参数来自动化捕获堆转储:

-XX:+ HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath = {HEAP-DUMP-FILE-PATH}

在 -XX:HeapDumpPath 中,需要指定堆转储所在的文件路径。传递这两个JVM参数时,将在抛出 OutOfMemoryError 时自动捕获堆转储并将其写入定义的文件路径。例:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof

一旦捕获了堆转储,就可以使用 HeapHero 和 EclipseMAT 之类的工具来分析堆转储。

每个应用程序将具有数十,数百,数千个线程。每个线程都有自己的堆栈。在每个线程的堆栈中,存储以下信息:

他们每个都消耗内存。如果它们的使用量超出某个限制,则会引发 StackOverflowError 。可以通过传递-Xss参数来增加线程的堆栈大小限制。例:

-Xss256k

如果将此 -Xss 值设置为一个很大的数字,则内存将被阻塞并浪费。假设您将 -Xss 值指定为 2mb ,而只需要 256kb ,那么您将浪费大量的内存。

假设您的应用程序有500个进程,然后 -Xss 值为 2Mb ,则您的线程将消耗 1000Mb 的内存。另一方面,如果您仅将 -Xss 分配为 256kb ,那么您的线程将仅消耗 125Mb 的内存。每个JVM将节省 875Mb 内存。

注意:线程是在堆(即 -Xmx )之外创建的,因此这 1000Mb 将是您已经分配的-Xmx值的补充。

现代应用程序使用多种协议(即SOAP,REST,HTTP,HTTPS,JDBC,RMI)与远程应用程序连接。有时远程应用程序可能需要很长时间才能做出响应,有时它可能根本不响应。

如果没有正确的超时设置,并且远程应用程序的响应速度不够快,则您的应用程序线程/资源将被卡住。远程应用程序无响应可能会影响您的应用程序的可用性。它可以使您的应用程序停止磨削。为了保护应用程序的高可用性,应配置适当的超时设置。

您可以在JVM级别传递这两个强大的超时网络属性,这些属性可以全局适用于所有使用 java.net.URLConnection 的协议处理程序:

sun.net.client.defaultConnectTimeout :指定建立到主机的连接的超时(以毫秒为单位)。例如,对于HTTP连接,它是与HTTP服务器建立连接时的超时。当建立与资源的连接时, sun.net.client.defaultReadTimeout 指定从输入流读取时的超时(以毫秒为单位)。

例如,如果您要将这些属性设置为2秒:

注意,默认情况下,这两个属性的值为-1,这表示未设置超时。

ZGC原理与实现分析

支持TB级堆内存(最大4T)

最大GC停顿10ms

对吞吐量影响最大不超过15%

SPECjbb 2015基准测试,128G堆内存,单次GC停顿最大1.68ms, 平均1.09ms

在对象的引用中借用几个bit存储额外状态标记,Load Barrier会根据这些状态标记执行不同的逻辑

加载屏障:在应用线程从堆中加载对象应用后,执行的一段逻辑

跟CPU中的内存屏障(Memory barrier)完全没有关联

目前ZGC没有分代,每次GC都会标记整个堆

将堆分为 2M(small), 32M(medium), n*2M(large)三种大小的页面(Page)来管理,根据对象的大小来判断在那种页面分配

在relocation阶段将Page中活的对象转移到另一个Page,并整个回收原Page。会根据一定算法选择部分Page进行整理。

大部分对象标记和对象转移都是可以和应用线程并发。只会在以下阶段会发生stop-the-world

1. GC开始时对root set的标记时

2. 在标记结束的时候,由于并发的原因,需要确认所有对象已完成遍历,需要进行暂停

3. 在relocate root-set 中的对象时

逻辑上一次ZGC分为Mark(标记)、Relocate(迁移)、Remap(重映射)三个阶段

Mark: 所有活的对象都被记录在对应Page的Livemap(活对象表,bitmap实现)中,以及对象的Reference(引用)都改成已标记(Marked0或Marked1)状态

Relocate: 根据页面中活对象占用的大小选出的一组Page,将其中中的活对象都复制到新的Page, 并在额外的forward table(转移表)中记录对象原地址和新地址对应关系

Remap: 所有Relocated的活对象的引用都重新指向了新的正确的地址

实现上,由于想要将所有引用都修正过来需要跟Mark阶段一样遍历整个对象图,所以这次的Remap会与下一次的Remark阶段合并。

所以在GC的实现上是2个阶段,即MarkRemap阶段和Relocate阶段

向下箭头表示STW, 横向箭表示并发阶段

在64位系统中,ZGC利用了对象引用的4bit( 低42位: 对象的实际地址)

Marked0/marked1: 判断对象是否已标记

Remapped: 判断应用是否已指向新的地址

Finalizable: 判断对象是否只能被Finalizer访问(本文分析忽略此标记)

这几个bits在不同的状态也就代表这个引用的不同颜色

为什么有2个mark标记?

每一个GC周期开始时,会交换使用的标记位,使上次GC周期中修正的已标记状态失效,所有引用都变成未标记。

GC周期1:使用mark0, 则周期结束所有引用mark标记都会成为01。

GC周期2:使用mark1, 则期待的mark标记10,所有引用都能被重新标记。

通过Linux系统调用mmap将标记位(001,010,100)三种地址空间映射到同一地址上,使三种地址解析后都指向同一地址,Load Barrer保证返回的地址是其中一个。

GC在每个阶段维护一个全局的唯一的期望标记,当发现引用的状态跟期望的不一致,Load barrier会修复应用的标记到期待的状态。并会根据状态的不同执行不同的逻辑。

下面分析不同阶段的实现流程

期待的标记值为001,此处只关注Mark操作,Remap逻辑下面说明。

当前加载的引用标记010,Load barrier会将引用的标记修正为001,然后保存回这个引用的来源对象中,这样在下次再加载相同时可以避免重复执行。同时会帮助GC进行对象标记,方式为将这个引用添加到当前线程的本地标记stack中,并发的GC线程会遍历这些引用,并递归遍历引用的对象图

期待的标记值为100

GC线程会执行为relocation set执行relocate工作,将page编辑为relocating(迁移中),只迁移对象,不关注对象的引用,relocation结束后,对象的引用会指向过期的位置。

此阶段业务线程加载对象引用时,进行remap操作:先判断指向的页面状态是否为relocating, 如果是relocating, 会协助GC线程做relocate工作。并更新此引用的的标记为100,如果不是relocating,直接更新标记为100。

当Relocation阶段完成时会存在部分引用未更新,标记为001。

来到下一次GC周期:

期待的标记值为010

如果当前加载的引用为100,表示已完成remap,更新标记为010

如果为其他状态,则会执行rmap操作,然后更新标记为010

同时会对对象进行mark操作,前面已经说明。

如此反复切换。

我们知道在一些GC算法下分配对象是通过撞指针法,也即是TLAB机制来分配。在ZGC中针对不同类型的Page,有不同的分配机制。

在堆上分配对象时,是根据对象的大小选择在不同类型的Page中分配,不同Page对象的分配策略不同。

Small Page(=256K): 每个CPU会关联一个small page,线程在分配对象时,先查找线程所运行在的cpu id, 找到关联的Page,进行分配。page剩余内存不够时,会尝试在新Page分配并切换cpu绑定的page为新的page。

Medium Page(=4M):  所有线程在同一个Page分配

Large Page: 每个large对象占用一个Page, 根据对象大小先分配合适大小的Page,然后在Page中分配对象

ZGC目前有4中机制触发GC

1. 定时触发, 默认为不使用,可通过ZCollectionInterval参数配置

2. 预热触发, 最多三次,在堆内存达到10%、20%、30%时触发,主要时统计GC时间,为其他GC机制使用

3. 分配速率, 基于正态分布统计,计算内存99.9%可能的最大分配速率,以及此速率下内存将要耗尽的时间点,在耗尽之前触发GC(耗尽时间 - 一次GC最大持续时间 - 一次GC检测周期时间)

4. 主动触发, (默认开启,可通过ZProactive参数配置) 距上次GC堆内存增长10%,或超过5分钟时,对比距上次GC的间隔时间跟(49 * 一次GC的最大持续时间),超过则触发

第一次STW, 标记roots对象

并发标记阶段,所有活对象以及对象引用都被标记

此后会有第二次STW,确保所有对象都被标记

选择需要整理的Page集合(relocation set)

第三次STW, 转移root中的对象

当一个Page内的活对象全部转移后,此Page的内存可以立即重用。

这是个和有用的特性,relocation set中下个page的对象可以转移到这个释放的内存中,理论上在GC时只需要有一个可转移的空页就可以了。

到此,一个GC周期就结束了。

剩下的修复工作由Load Barrier以及下次GC来完成

docker 中 jvm 参数设置的坑

比如,启动java 程序的时候设置 max heap =32g,发现线程程序模拟奇妙的被杀死。

cause: docker 设置应用内存为30g。

比如jvm 的内存在30g的时候,以为还有内存,不会做gc,然后就被docker 杀死了。

这个就是为什么,过一段时间,我们的程序就被kill,但是也不做gc 释放内存。

另外的问题, 设置 xmx 为7G。容器内存为8G。 但是也会出现kill掉的原因; 为啥?

jvm 的进程可以通过top 来查看内存使用。超过8G。 jvm 除了堆,还有各种其他内存,栈,元空间,堆外内存,native,code cache等; 所以 这buffer 要设置的多一点; 或者针对每个buffer的地方设置限制;

参考:

我们的 eden 大概10个g,比较大,但是 youungc 打印log看

这个是无法接受的。

我们的jdk8,默认的是 UseParallelGC, young 区用的是 paraNew的 并发收集算法

虽然 UseParallelGC,关注吞吐,可能单次回收时间慢一点,1s 我觉得是正常的,尼玛一看30s,不可能的。

jstack 看,分配了23个gc线程。

年轻代的并行收集线程数默认是(ncpus = 8) ? ncpus : 3 + ((ncpus * 5) / 8),如果你希望设定这个线程数,可以通过-XX:ParallelGCThreads= N 来调整。

可以看到,docker 拿的是宿主机的 cpu数目,但是docker 容器有一个 核的限制。

我们一看资源,大概就是 2个cpu。

结果24个cpu去收集垃圾,但是只有2个核心,造成了大量的竞争,所以非常慢。

指定成2个cpu,gc 时间回到 1s级别。

后续看下来,还是有2s左右的停顿:

通过gc log 看,时间在 youngc 的时候不太稳定, 有时候能到1-2s的停顿

默认使用的 parallel scaverage, 吞吐量优先。 有可能存在一个 大的停顿。

parallelNew,就是普通的并发,没有吞吐量优先,可能效果好稍微好点。

影响 停顿的几个变量, young 区的大小, gc 线程的数目, 以及 选用的算法。

目前看使用 g1, 回收次数变多,但是平均时间相对是最小的。

考虑到线上4个线程:

我们在167 上试用 3个类型的 gc 算法:

1) parallel scaveage:

4 次yonguc,1.3s,平均 300ms,3次full gc。meta比较快,最大0.52s

2) parallel new:

4次 youngc,0.7s。平均 170ms。 3次 full gc。meta 区,做大0.3s。

3) g1:

18次,2.3s。平均 120ms,最大 0.35s。

看起来G1 比较优秀。

如果是 java11,可以使用更优秀的;zgc,低延迟可以做到更低。

参考美团的大作:

47 jvm性能优化之GC日志参数分析

回收算法

标记清除算法

根据gcRoot对象的引用链,发现如果该对象没有被引用的情况下,

则标记为垃圾,在清除。

优点:算法简单

缺点:容易产生内存碎片

标记整理算法

根据gcRoot对象的引用链,发现如果该对象没有被引用的情况下,

则标记为垃圾

标记整理与标记清除区别在于:避免标记清除算法产生的碎片问题,

清除垃圾过程中,会将可用的对象实现移动,内存空间更加具有连续性。

优点:没有内存的碎片问题

缺点:整理过程中会产生内存地址移动,效率可能偏低。

标记复制算法

根据gcRoot对象的引用链,发现如果该对象没有被引用的情况下,

将正在被引用的对象拷贝到to区中,让后再直接清理整个from区,在交换位置。

优点:不会产生内存碎片

缺点:比较占内存空间

分代算法

分代算法中主要分成三代: 新生代/from或者 to/老年代

默认 新生代(Young)与老年代(Old)的比例的值为 1:2 (该值可以通过参数–XX:NewRatio 来指定)。

默认的 Eden:from:to=8:1:1 (可以通过参数 –XX:SurvivorRatio 来设定)。

新生代:刚创建的对象都存放在新生代中eden区,当eden区空间内存满之后,则根据GC可达分析算法,将幸存的对象拷贝到to区中,并且寿命+1. 如果该对象的寿命15的情况下

则将该对象放入到老年代中。

老年代:Minor GC新生代GC ,回收多次如果该对象还一直被引用的情况下,则放入到老年代中,如果新生代和老年代内存都满的情况下,则会触发FullGC

总结:

1.对象首先分配到eden区(伊田园区) 新生代GC (Minor GC)

2.新生代空间不足时,触发Minor GC,将eden区(伊田园区)存活的对象采用标记复制算法放入到to区中,并且该对象的寿命+1

注意:Minor GC因为标记复制算法,会触发stop the world 暂停其他用户的线程,等待垃圾回收结束之后,其他的用户线程才会继续执行。

3.如果该对象的寿命15的情况下,则将该对象放入到老年代中,对象寿命放入在对象头中。

4.当老年代空间不足的时候,会触发FullGC 采用标记清理/整理算法

5.新生代GC非常频繁,速度比老年代GC要高。

GC相关参数

Stop-The-World

在垃圾回收过程中经常涉及到对对象的挪动(比如上文提到的对象在Survivor 0和Survivor 1之间的复制),进而导致需要对对象引用进行更新。为了保证引用更新的正确性,Java将暂停所有其他的线程,这种情况被称为“Stop-The-World”,导致系统全局停顿。Stop-The-World对系统性能存在影响,因此垃圾回收的一个原则是尽量减少“Stop-The-World”的时间。

回收算法:

误区:没有引用计数算法

1.标记清除算法

2.标记整理算法

3.标记复制算法

回收算法是针对不同的场景使用

按照分代使用

新生代:标记复制算法

老年代:标记清除/标记整理

为什么新生代使用 标记复制算法?而老年代使用标记清除/标记整理

为什么新生代使用 标记复制算法?而老年代使用标记清除/标记整理

因为新生代gc非常频繁,所以选择效率比较高的垃圾回收算法。、

标记清除算法:

优点:算法非常简单。

缺点:空间地址不连续

为什么标记清除算法:空间地址不连续 没有整理

标记整理算法:

优点:空间地址保持连续

缺点:速度慢、会产生移动内存地址 在移动过程中其他线程无法访问堆内存。

标记复制算法:

优点:空间地址保持连续、效率比标记整理算法要高。

缺点: 存在两个空间,占用空间。

分为两个区域:from 和to区 相等。

From和to切换

原理:

当我们堆内存触发gc的时候,在from区中将可用对象拷贝到to中,在直接将整个from

区清空,依次循环切换。

垃圾收集器 并行、串行、cms g1

分代算法:

首先,对我们堆内存空间实现分代,核心分为新生代、老年代

新生代:刚创建的对象一般的情况下都是放在新生代中

分为:eden区() from区 to区

刚创建的对象会放在eden区,当我们新生代eden区空间满的

情况下,会将引用的对象拷贝到to区中,如果gc回收15次的时候

发现该对象还一直被使用的情况下,该对象就会晋升为老年代中。

老生代:

存储空间比例:

1.默认的情况下新生代与老年代存储空间比例是1:2

2.新生代中eden区与from/to区

为什么新生代中from/to区 比例是1:1

因为新生代中使用的标记复制算法

老年代在什么的情况下会发生fullgc

1.在新生代和老年代有堆内存空间都快满的时候。

新生代GCMinorGC

老年代fullgc

当我们老年代gc开始回收垃圾的时候,也会触发新生代gc回收。

老年代在什么时候触发:

当我们老年代空间装不下的时候。

依次内推如何演示新生代gc

Java垃圾收集算法 cms、g1收集器

1.标记清除、标记整理、标记复制算法(引用计数法)

1.标记清除算法:

优点:算法实现简单

缺点: 内存空间不连续、空间利用率不高 容易产生碎片化

2.标记整理算法

优点:空间具有连续性 没有产生碎片化的问题 效率比较低

缺点:对象的应用内存地址有可能会发生变化

3.标记复制算法

优点:效率比较高,保证空间连续性的问题

缺点:以空间的方式换时间

分代算法:

分为新生代和老年代

新生代:刚创建的对象都存放到新生代中 ,在新生代中有分成三个区域。

新生代中分为 eden区、from和to区

刚创建的对象存放到eden区,当eden区如果满的时候,幸存的对象晋升为存放到

From或者是to区

新生代触发的GCMinorGC

老年代触发的GCFullGC

那些对象会晋升到老年代中?

1.年限达到当gc多次在回收的时候,如果能够一直引用到一个阈值的情况下。直接晋升到老年代中。

2.直接是大对象

在默认的情况下 新生代与老年代存储空间比例 是为1:2

在默认的情况下,新生代中 eden区域与from或者是to占比是为8:1:1

程序发生内存溢出:存放的对象空间大小大于我们老年代的空间大小。

因为在整合堆内存中,新生代触发gc回收次数一定比老年代多。

为什么在分代算法中 新生代中有from和to区大小一样。

因为新生代中gc触发非常频繁,为了能够更加高效清理垃圾,所以采用标记复制算法。

垃圾收集器在什么开始触发收集垃圾?

当新生代或者是老年代内存满的情况下,开始触发垃圾

垃圾收集器之前频繁推出垃圾收集器

Stop-The-World 问题

Stop-The-World:当我们垃圾收集器在回收垃圾的时候,

当垃圾回收线程在清理垃圾的时候,会暂停我们的所以用户线程。

导致当前的用户线程短暂卡

在生产环境中调优jvm: 不要频繁触发垃圾回收或者是降低用户线程阻塞的时间

所有的收集器:在回收垃圾的时候都会暂停我们用户的线程

怎样避免触发垃圾收集器频繁回收?

1.堆内存空间设置比较大

2.堆内存初始化 与最大值一定保持一致。

3.生产环境中不要去调用System.gc();

垃圾收集器 与垃圾收集算法区别:

垃圾收集器:串行、并行收集、CMS、G1 Java11 ZGC收集器,能够降低对我们用户线程暂停的时间或者用户线程和GC线程同时运行

垃圾收集算法:回收算法:标记清除、标记整理、标记复制、分代算法

Stop-The-World

当我们在触发gc回收的时候,有可能会暂停用户的线程。

JVM参数

如果存放的对象空间大于新生代空间,该对象会直接放到老年代中。

GC核心参数

-Xms100 -Xmx

1、-Xms

初始大小内存,默认为物理内存 1/64,等价于 -XX:InitialHeapSize

2、-Xmx

最大分配内存,默认为物理内存的 1/4,等价于 -XX:MaxHeapSize

3、-Xss

设置单个线程栈的大小,一般默认为 512-1024k,等价于 -XX:ThreadStackSize

4、-Xmn

设置年轻代的大小

整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小

持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

5、-XX:MetaspaceSize

设置元空间大小

元空间的本质和永久代类似,都是对 JVM 规范中的方法区的实现。

元空间与永久代之间最大区别:元空间并不在虚拟机中,而是使用本地内存

因此默认情况下,元空间的大小仅受本地内存限制,元空间默认比较小,我们可以调大一点

6、-XX:+PrintGCDetails

输出详细GC收集日志信息

7、-XX:SurvivorRatio

设置新生代中 eden 和 S0/S1 空间比例,默认 -XX:SurvivorRatio=8,Eden : S0 : S1 = 8 : 1 :

8、-XX:NewRatio

配置年轻代和老年代在堆结构的占比,默认 -XX:NewRatio=2 新生代占1,老年代占2,年轻代占整个堆的 1/3

9、-XX:MaxTenuringThreshold

设置垃圾最大年龄

新生代与老年代参数比例设置

-XX:+PrintGCDetails -verbose:gc -XX:SurvivorRatio=2 -XX:NewRatio=1

GC日志参数分析

[GC (Allocation Failure) [PSYoungGen: 1626K-488K(6144K)] 1626K-688K(19968K), 0.0039387 secs] [Times: user=0.14 sys=0.00, real=0.00 secs]

新生代发生GC ,从堆内存回收前占用:1626k 回收后变为占用488K ,后面表示GC的用时。

[Full GC (Allocation Failure) [PSYoungGen: 488K-0K(6144K)] [ParOldGen: 296K-593K(13824K)] 784K-593K(19968K), [Metaspace: 3099K-3099K(1056768K)], 0.0043821 secs]

当发生老年代GC时,也会触发新生代GC,新生代堆回收前占用488K,回收后占用0K

,ParOldGen 老年代回收前占用784K,回收后占用593K

GC分析大对象

当我们直接存一个大的对象的时候,比新生代占用空间还有大时,会直接晋升为老年代。

zgc具体流程

zgc具体流程:

通过-Xmx10g进行设置。

-Xmx是ZGC收集器中最重要的调优选项,大大解决了程序员在JVM参数调优上的困扰。ZGC是一个并发收集器,必须要设置一个最大堆的大小,应用需要多大的堆,主要有下面几个考量:

对象的分配速率,要保证在GC的时候,堆中有足够的内存分配新对象

一般来说,给ZGC的内存越多越好,但是也不能浪费内存,所以要找到一个平衡。

Concurrent GC Threads

通过-XX:ConcGCThread = 4进行设置。

并发执行的GC线程数,如果没有设置,在JVM启动的时候会根据CPU的核数计算出一个合理的数量,默认是核数的12.5%,但是根据应用的特性,可以通过手动设置调整。

因为在并发标记和并发移动时,GC线程和应用线程是并发执行的,所以存在抢占CPU的情况,对于一些对延迟比较敏感的应用,这个并发线程数就不能设置的过大,不然会降低应用的吞吐量,并有可能增加应用的延迟,因为GC线程占用了太多的CPU,但是如果设置的太小,就有可能对象的分配速率比垃圾收集的速率来的大,最终导致应用线程停下来等GC线程完成垃圾收集,并释放内存。

一般来说,如果低延迟对应用程序很重要,那么不要这个值不要设置的过于大,理想情况下,系统的CPU利用率不应该超过70%。

Parallel GC Threads

通过-XX:ParallelGCThreads = 20

当对GC Roots进行标记和移动时,需要进行STW,这个过程会使用ParallelGCThreads个GC线程进行并行执行。

ParallelGCThreads默认为CPU核数的60%,为什么可以这么大?

因为这个时候,应用线程已经完全停下来了,所以要用尽可能多的线程完成这部分任务,这样才能让STW尽可能的短暂。

Java设置ZGC的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java设置excel单元格格式、Java设置ZGC的信息别忘了在本站进行查找喔。