概述
生产系统的稳定性非常重要。 JVM内存越大,内存溢出的风险越低。只要主机内存允许,在JVM上浪费更多的内存是可以理解的。但是,使用较少的资源来发挥更大的作用是正确的方法,因此应该合理地设置JVM内存。
不同的Java应用程序具有不同的内存要求。仅在每个应用程序的实际运行期间收集内存使用情况数据之后,才能确定适当的JVM参数。也就是说,首先设置初始值,然后在应用程序运行期间收集内存使用情况数据,最后计算每个内存区域的大小。
本文主要说明如何初步确定新应用程序的内存参数。至于更详细的优化方案,则不再赘述。
JDK8内存模型的基本知识
在JDK8中的内存区域划分中,删除了先前版本的持久性区域(PermGen)。 -XX:PermSize和-XX:MaxPermSize参数无效,并且不会发生java.lang.OutOfMemoryError:PermGen异常。相反,它是元空间。元空间GC独立于堆GC。
堆内存模型:

JVM的默认比率为Eden:S0:S1:Tenured = 8:1:1:20。 JVM“浪费”了S1,也就是说,实际上只有39个内存副本将数据存储在40个内存副本中。
Old:New = 2:1,对应于参数–XX:NewRatio = 2; Eden:S0 = 8:1,对应于参数–XX:SurvivorRatio = 8。
堆区域中的内存恢复分为新区域中的YGC和旧区域中的FGC。
参数
-Xms128M:设置最小堆内存
-Xmx128M:设置最大堆内存
-XX:NewSize = 64M:设置新区域的最小值
-XX:MaxNewSize = 64:设置新区域的最大值

-XX:NewRatio = 2:设置旧区域与新区域的比例
-Xmn64M:设置新区域的大小,它等效于两个参数-XX:NewSize = 64M和-XX:MaxNewSize = 64M。设置此值后,-XX:NewRatio无效。
-XX:SurvivorRatio = 8:设置Eden面积与两个S面积之和的比例
-verbose:gc:输出每个GC的相关信息
-Xloggc:../logs/gc.log日志文件的输出路径
-XX:+ PrintGC:输出GC日志
-XX:+ PrintGCDetails:输出GC的详细日志
-XX:+ PrintGCTimeStamps:输出GC时间戳(以基本时间的形式)
-XX:+ PrintGCDateStamps:输出GC时间戳(以日期形式,例如2019-11-20T21:53:5 9. 234 + 080 0)
-XX:+ PrintHeapAtGC:打印出GC之前和之后的堆信息
GC的基本要点
在Eden区域中创建了新对象,并且Eden区域不足以触发YGC。 Eden区域中仍然没有足够的空间来在Old区域中创建对象。
新对象的大小超过-XX:PretenureSizeThreshold参数(默认值为0),该大小直接在旧区域中创建。
在YGC期间无法将尚存的对象存储在S1(至太空)区域中,因此请将尚存的对象移动到“旧”区域。
在YGC期间,幸存对象的数量gc超过-XX:MaxTenuringThreshold(默认值1 5),然后将幸存对象转移到旧区域。
当旧区域中的内存不足时,将触发FGC。如果空间不足,则JVM会抛出OutOfMemoryError。

内存数据收集工具
借助JDK自己的命令行jstat -gc pid,显示的大小为KB。
该字段的含义为C:总容量,U:已使用容量,S0,S1:幸存者区域,E:伊甸园区域,O:旧区域,M:元空间,CC:CompressedClassSpaceSize,YGC:回收时间青年区,YGCT:YGC的总时间,FGC:旧区的恢复时间,FGCT:FGC的总时间,GTC:YGCT + FGCT。
例如jstat -gc11925
您还可以使用jmap -heap pid命令显示堆内存状态。
JVM参数调整过程
用于打印GC日志的参数:-verbose:gc -Xloggc:gc.log -XX:+ PrintGC -XX:+ PrintGCDateStamps -XX:+ PrintHeapAtGC
可以将gc.log设置为实际路径。
第一阶段(设置堆区域的总内存)
目标:仅设置堆区域的总内存,并对JVM的每个区域使用默认比率
参数:-Xms128M -Xmx128M
在运行该应用程序一段时间后,多次采样数据:
gstat -gc 11925
jmap -heap 11925


您可以看到2个FGC,470 YGC,GC频率已通过。分析数据后发现两个问题:一、旧区域的利用率非常低,仅占17%,128M的内存仍然有点浪费; 二、伊甸园地区的利用率非常高,天然YGC的数量确实更高。
首先减少总内存,然后根据上述数据= 28M + 14M,即42M,计算应用程序所需的总内存。但是To Space会浪费2. 5%(1/4 0)内存,限制堆区域内存= 42 /(1- 2. 5%)= 4 4. 21M,它应该可以使用整数并使用64M Satisfied,即参数:-Xms64M -Xmx64M。64M大约是1.内存的5倍。如果不用担心,您可以使用89M内存的2倍,并使用整数: -Xms96M -Xmx96M。
使用限制的内存大小可以满足应用程序的基本操作,但是可以预见的结果是FGC的频率将非常高。
注意:上面的算法使用Eden + S0 + Old作为堆内存的可用空间。考虑到极端情况,在经过特定的YGC之后,伊甸园区域中的所有对象都将转移到旧区域。因此,保险点的限制记忆应基于旧区域。在上面的示例中,应确保旧区域的大小不小于42M,并且限制堆区域的内存= 42 /(2 / 3) = 63M。
第二阶段(调整新区域的内存)
目标:降低YGC的频率
参数:-Xms128M -Xmx128M -Xmn64M
以前面的示例为例,应用程序在统计数据中生成的对象占用42M的内存,而New区域的容量为38M,总堆内存为128M,理论上的空闲空间为80M,因此在新区域中超过4200万并不夸张。
修改后,jstat -gc 14854的实际测量值显示出很小的差异。

三个阶段(调整伊甸园和幸存者)
目标:减少YGC时,由于缺少生存空间而直接转移到旧区
参数:-Xms128M -Xmx128M -Xmn64M-XX:SurvivorRatio = 4
伊甸园和生存者是矛盾的。当伊甸园与幸存者的比例较大时,由于在YGC期间S1(To)区域中的空间不足,因此数据会直接传输到旧区域。当比率较小时,S1空间浪费更多。
通常说二十八法则,但是-XX:SurvivorRatio = 8中的8是伊甸园面积与两个S面积之和的比率。将Eden与S0面积的比率设置为8是不安全的。将1:1更改为8:2:2,对应于-XX:SurvivorRatio = 4。推荐值在4到8之间。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-375177-1.html
性
还真的是
亲爱的
请问你夫人今晚有空吗