堆空间的常用配置

-Xms -Xmx 设置堆空间的大小 推荐设置成相同 -Xmx8G -Xms8G 可以防止JVM动态调整而消耗性能

-Xss512: 设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所

需内存大小进行调整。在相同物理内 存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的

不能无限生成,经验值在3000~5000左右。

---------------堆空间相关配置------------------

-XX:NewSize: -XX:MaxNewSize: 新生代 最大新生代 这个优先级优于下面

-Xmn 相当于 NewSize = MaxNewSize 这个优先级优于下面

-XX:NewRatio=3 意味着年轻代和老年代之间的比率为1:3。也就是说伊甸园和幸存者空间的总大小将是堆总大小的四分之一 这个优先级最低 默认值是2

-XX:SurvivorRatio=8 默认是8 eden:Form:To = 8:1:1 比如:SurvivorRatio=6。那么幸存者空间将是年轻一代的八分之一(而不是七分之一,因为有两个幸存者空间)。

-XX:MetaspaceSize: -XX:MaxMetaspaceSize 元空间大小 JDK8以后使用的本地内存 要控制好范围

-XX:MaxDirectMemorySize=2G 直接内存 默认和堆内存最大值一样 不受java堆大小限制 NIO零拷贝会用到 最好设置约束下

-XX:MaxTenuringThreshold=threshold 设置自适应GC分代中使用的最大使用阈值。最大的值是15。对于并行(吞吐量)收集器,默认值是15,对于CMS收集器,默认值是6。

-XX:-UseTLAB 关闭 TLAB:ThreadLocalAllocBuffer 事先在堆里面为每个线程分配一块私有内存 原子性 默认开启(建议开启)

-XX:TLABSize=512k 设置TLAB的大小

-XX:PretenureSizeThreshold 默认0不管多大都是先在eden中分配内存 当超过eden区的大小的时候,才分配到old区。

大于该值大小的对象直接在老年代分配(单位字节) 自己看着办设置

-XX:+DoEscapeAnalysis 开启逃逸分析 对象作用域逃出函数 就是在方法new了个对象并把这个对象返回出去了 需要配合下面一起才生效 默认开启

-XX:+EliminateAllocations 标量替换 分析出成员变量没有逃逸 把其分配到局部变量也就是栈中 这样就不需要垃圾回收 默认开启

CMS参数配置说明

1、增量收集 -XX:CMSInitiatingOccupancyFraction=80 判断当前 Old 区使用率是否大于阈值,则触发 CMS GC 默认百分之92 降低触发CMS GC的阈值,

让CMS GC尽早执行,以保证有足够的连续空间,也减少 Old 区空间的使用大小

另外需要使用 -XX:+UseCMSInitiatingOccupancyOnly 来配合使用,不然 JVM 仅在第一次使用设定值,后续则自动调整

-XX:+ParallelRefProcEnabled 对 Reference 进行并行处理。

-XX:+CMSClassUnloadingEnabled 这会使得 CMS 在 CMS-Remark 阶段尝试进行类的卸载 对 MetaSpace 或 Perm 进行垃圾收集,默认关闭, ps:最好不要处理

2、内存碎片 -XX:+UseCMSCompactAtFullCollection 来控制 Full GC的过程中是否进行空间的整理(默认开启 是Full GC,不是CMS GC)

-XX:CMSFullGCsBeforeCompaction=0 来控制多少次 Full GC 后进行一次压缩

3、浮动垃圾: 视情况控制每次晋升对象的大小,或者缩短每次 CMS GC 的时间,必要时可调节 NewRatio 的值。

另外就是使用 -XX:+CMSScavengeBeforeRemark 在FullGc过程中提前触发一次 Young GC,防止后续晋升过多对象。

ZGC参数配置说明

-XX:ReservedCodeCacheSize -XX:InitialCodeCacheSize:设置CodeCache的大小, JIT编译的代码都放在CodeCache中,一般服务64m或128m就已经足够。

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC:启用ZGC的配置。

-XX:ConcGCThreads:并发回收垃圾的线程。默认是总核数的12.5%,8核CPU默认是1。调大后GC变快,但会占用程序运行时的CPU资源,吞吐会受到影响。

-XX:ParallelGCThreads:STW阶段使用线程数,默认是总核数的60%。

-XX:ZCollectionInterval:ZGC发生的最小时间间隔,单位秒。

-XX:ZAllocationSpikeTolerance:ZGC触发自适应算法的修正系数,默认2,数值越大,越早的触发ZGC。

-XX:+UnlockDiagnosticVMOptions -XX:-ZProactive:是否启用主动回收,默认开启,这里的配置表示关闭。

GC日志中每一行都注明了GC过程中的信息,关键信息如下:

Start:开始GC,并标明的GC触发的原因。上图中触发原因是自适应算法。

Phase-Pause Mark Start:初始标记,会STW。

Phase-Pause Mark End:再次标记,会STW。

Phase-Pause Relocate Start:初始转移,会STW。

Heap信息:记录了GC过程中Mark、Relocate前后的堆大小变化状况。High和Low记录了其中的最大值和最小值,我们一般关注High中Used的值

如果达到100%,在GC过程中一定存在内存分配不足的情况,需要调整GC的触发时机,更早或者更快地进行GC。

GC信息统计:可以定时的打印垃圾收集信息,观察10秒内、10分钟内、10个小时内,从启动到现在的所有统计信息。利用这些统计信息,可以排查定位一些异常点。

image.png

个人建议

1、设置-Xms -Xmx 设置成一样的大小 减少动态调整分代带来的开销(本地提前测试 一般情况下 永久代的大小应当为活跃对象的 2~3 倍左右,考虑到浮动垃圾问题最好在 3 倍左右,剩下的都可以分给 Young 区)。

2、栈大小一般 256k 就够用了(除非代码中有很深的调用链)。

3、方法区内存: 与堆处于平行的空间 不属于堆和栈。

4、在一个方法区内频繁创建对象 为了避免GC大量回收 可以开启逃逸分析 jdk1.8默认开启。

栈空间的内存 随着线程的销毁而销毁 在栈上分配的对象所以不需要GC。

5、CGLIB技术直接操作字节码运行 生成大量的动态类会导致,jvm堆永久代内存溢出,排查问题困难,在使用的时候一定要谨慎。

6、偏向锁在只有一个线程使用到该锁的时候效率很高,但是在竞争激烈情况会升级成轻量级锁,此时就需要先消除偏向锁,这个过程是 STW 的。如果每个同步资源都走这个升级过程,开销会非常大,所以在已知并发激烈的前提下,一般会禁用偏向锁 -XX:-UseBiasedLocking 来提高性能。

通用配置 (java $通用配置 -jar ***.jar)

-XX:+PrintGCDetails 开启打印GC详细过程 并不会占用什么资源

-XX:+PrintGCTimeStamps | -XX:+PrintGCDateStamps 时间间隔 | 系统时间 方便看GC发生频率

-XX:+HeapDumpOnOutOfMemoryError 发生内存溢出时 自动生成dump日志

-Xloggc:'gc.log' 指定GC日志的地方

-Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/opt/logs/logs/gc-%t.log:time,tid,tags:filecount=5,filesize=50m

GC日志说明

[图片上传中...(image-c2b5f4-1600391556819)]