内存使用分析
free -m 查看内存使用情况,最好没有swap,有最好禁用。
jstat -gcutil <pid> 3s 3 重点是O(老年代)和FGCT\FGC,如果单次FGC时间很长,会影响服务可用。
jmap -histo <pid> | head -n20 查看实例数,找到怀疑的对象,一般都是自己写的类
jmap -histo:live <pid> | head -n10 触发一次fullGC,查看gc后的实例数,这个最好不要在现网用,可能会很慢。
观察怀疑的对象数量有没有下降,如果还没有下降,就基本判定是该对象导致的内存泄露,如果FullGC完,只剩下java自带的类,那就证明没有泄露。
触发fgc之后,FGC之后次数+1,FGCT变为大,O区变小。
对于实时性要求高的服务
比如在腾讯云上搭建了一个Minecraft server,作为一个实时游戏,使用java做server,一秒20次tick,一旦fgc,大概率会卡顿。
优化的思路为,减少大gc,尽可能多次小gc.尽量让短生命周期对象不要进入老年代。
可以根据qps和请求体大小,评估eden区的清理频率
minor gc过程中的时间中,新产生的垃圾占满eden后可能会进入servivor区,也有可能直接进入老年代(比如触发动态年龄机制:短周期的对象占用超过survivor区50%)。
如果把eden区和s区调大,就很少会有对象进入老年代
"-X"开头的参数是非标准参数,不能被全部VM识别的参数。
"-XX"开头的参数是非稳定参数
java -server -d64 -Xmx1000M -Xms1000M 指定server模式,会提高性能,堆内存总大小大小s和x一样可以避免内存重新分配
整个堆大小=年轻代大小 + 年老代大小 + 持久代大小
-Xmn400M 年轻代,也就是eden+survivor1和2,一般为堆内存3/8,这个相当于下面两句
-XX:NewSize=400M :设置年轻代初始值为400M 。
-XX:MaxNewSize=400M :设置年轻代最大值为400M 。
-XX:PermSize=128m:设置持久代初始值为128m。
-XX:MaxPermSize=128m:设置持久代最大值为128m。
-XX:NewRatio=3:设置年轻代(包括1个Eden和2个Survivor区)与年老代的比值。表示年轻代比年老代为1:3。
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的比值。表示2个Survivor区与1个Eden区的比值为2:4,即1个Survivor区占整个年轻代大小的1/6。
-Xss128k 线程的栈大小,调太大会导致oom:native thread,配和ulimit -a和-u使用
-XX:MaxTenuringThreshold=7:表示一个对象如果在Survivor区(救助空间)移动了7次还没有被垃圾回收就进入年老代。
-Xverify:none 关闭字节码校验。改善启动速度
-Xnoclassgc 禁用类卸载可能可以改善 GC 表现
-XX:+UnlockExperimentalVMOptions
-XX:MaxGCPauseMillis=100
-XX:+UseParallelOldGC 适合小型服务器
-XX:+UseG1GC 使用g1垃圾收集器
-XX:G1NewSizePercent=50
-XX:G1MaxNewSizePercent=80
-XX:G1MixedGCLiveThresholdPercent=35
-XX:AutoBoxCacheMax=(缓存最大值) 默认为128,设置为更大值让 Integer 缓存更多元素,略微减少后续内存分配,可以考虑填大一些的数(譬如20000).
-XX:+AlwaysPreTouch 让 JVM 开启时预先访问一遍内存,可以让后续使用更平滑,但启动时间会增加
-XX:FreqInlineSize=325
-XX:MaxInlineSize=420 内联大小调大可以提供性能 较大的size可能导致cpu缓存效率低
-XX:InlineSmallCode=2000
-XX:MinInliningThreshold=250
-XX:+UseStringDeduplication 能导致轻微性能下降,但对内存占用有所改善
-XX:+ExplicitGCInvokesConcurrent 使得用 System.gc() 调用后可以不阻塞,并行的回收内存,与 GC 算法配置相关,建议多核环境启用。
-XX:+ParallelRefProcEnabled
不同JDK jVM的性能也不一样的
G1 边使用边回收,满足gc时间