堆内存用于存储new对象,垃圾回收器负责堆内存的管理。但Java程序实际占用的空间则由堆内存、栈内存(程序运行栈)、程序计数器、常量区、代码区、本地内存等。
堆内存分为Young和Old,Young分为2个Survivor (From Survivor和To Survivor),1个eden,具体见JVM系列-垃圾回收。
-Xms??[m|g]
初始堆内存大小,默认为物理内存的1/64,单位是Byte
-Xmx??[m|g]
最大堆大小,默认为物理内存的1/4,单位是Byte。虽然程序申请了内存空间,但物理内存还是由程序实际需要来分配(这就是计算机原理了,虚拟地址空间和物理内存的关系)。
-XX:NewRatio = ??
Young与Old的分配,默认为2(young:old=1:2),NewRatio越大,old空间越大。
–XX:SurvivorRatio = ??
Survivor与Eden的分配,默认为8(Survivor:Eden=1:8),SurvivorRatio越大,Eden区间越大。注意这是一个Survivor与Eden的比例,所以Young如果分成10份,则2个Survivor共占2份,Eden占8份。
内存大小和GC的关系
大内存空间:减小GC执行次数,增加单次GC执行时间;小内存空间:减小单次GC执行时间,增加GC执行次数
查看默认值
java -XX:+PrintFlagsFinal -version | grep NewRatio 查看NewRatio
java -XX:+PrintFlagsFinal -version | grep -i heapsize 查看初始堆/最大堆的大小
在程序优化的时候需要观察gc情况,所以需要设置一些参数。
-XX:+PrintGCDetails 打印GC详情,会显示Minor/Full gc的内存变化、持续时间等具体情况
-XX:+PrintGCDateStamps 打印GC日期类型的时间
-Xloggc:/home/work/log/gc.log GC日志存储路径
SafePoint是线程状态,表示线程目前处于一个稳定状态,可以停止或进行其他调度,GC等其他操作需要SafePoint。SafePoint的特定代码位置主要有:循环末尾、方法return前、方法call返回后、异常抛出位置等。
打印SafePoint信息,显示程序停止时间
-XX:+PrintApplicationStoppedTime(程序暂停了多少时间) -XX:+PrintGCApplicationConcurrentTime(两次连续暂停的时间间隔)
打印引起SafePoint的操作、线程运行情况等
-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1
如下图可以看出引起STW(Stop the World)的操作有Depotimize/GC/RevokeBias等,这些操作都需要等待程序处于SafePoint状态。
no vm operation说明是一个保证安全点GuaranteedSafepoint(具体作用待续),默认每秒执行一次。
查看GuaranteedSafepoint的时间间隔:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal 2>&1 | grep Safepoint
设置间隔时间:
-XX:GuaranteedSafepointInterval=0 (关闭) -XX:GuaranteedSafepointInterval=1000 (1000ms)
4.何时需要GC优化
GC应该是程序优化的最后一步,GC执行的次数与创建对象的数量成正比,GC次数多的时候应该首先减少创建对象的数量。
满足以下条件无需GC:
可以通过jstat -gcutil pid来查看GC情况,S0/S1/E/O/P分别表示survivor、eden、old、permanent空间已用百分比,YGC/YGCT表示Young GC的次数和总共耗时(单位秒),FGC/FGCT表示Full GC的次数和总耗时,GCT=YGCT+ FGCT。
GC一些原则:
-Xmn
选项或 -XX:NewRatio
等其他相关选项显式设置年轻代大小