「Java设置ZGC」java设置excel单元格格式
今天给各位分享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的信息别忘了在本站进行查找喔。