GC常用参数
- -Xmn -Xms -Xmx -Xss
年轻代 最小堆 最大堆 栈空间大小 - -XX:+UseTLAB
使用TLAB,默认打开 - -XX:+PrintTLAB
打印TLAB的使用情况 - -XX:TLABSize
设置TLAB大小 - -XX:+DisableExplictGC
System.gc()不管用 ,FGC - -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintHeapAtGC
- -XX:+PrintGCTimeStamps
- -XX:+PrintGCApplicationConcurrentTime (低)
打印应用程序时间 - -XX:+PrintGCApplicationStoppedTime (低)
打印暂停时长 - -XX:+PrintReferenceGC (重要性低)
记录回收了多少种不同引用类型的引用 - -verbose:class
类加载详细过程 - -XX:+PrintVMOptions
- -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
必须会用 - -Xloggc:opt/log/gc.log
- -XX:MaxTenuringThreshold
升代年龄,最大值15 - 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 …
这些不建议设置
JVM调优第一步:了解JVM常用命令行参数
public class HelloGC {
public static void main(String[] args) {
System.out.println("hello gc~");
List<byte[]> list = new LinkedList<>();
for (; ; ) {
list.add(new byte[1024 * 1024]);
}
}
}
区分概念:内存泄漏memory leak,内存溢出out of memory
内存泄漏就是有一块内存,我们用不到 但是GC也无法回收
内存溢出是分配内存时,发现内存不够用啦
这俩其实没啥必然的联系:
泄漏不一定导致溢出,内存总空间够大的话,浪费一点也不致命;
内存溢出不一定是由内存泄漏导致,内存总空间比较小,程序的对象又很多时,正常的使用也可能内存溢出
-XX:+PrintCommandLineFlags
输出JVM的默认参数:
-Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC
- -Xmn 年轻代空间的最大值,-XX:MaxNewSize
- -Xms 堆空间的最小值,-XX:InitialHeapSize,即初始大小
- -Xmx 堆空间的最大值,-XX:MaxHeapSize
一般把Xms和Xmx设置成一样的大小,避免堆的扩容和缩容所带来的资源消耗 - -XX:+PrintGC 打印GC信息
关于打印GC的参数还有:
-XX:+PrintGCDetails 打印详细信息,这个下面详细看
-XX:+PrintGCTimeStamps 时间戳
-XX:+PrintGCCause 原因
执行后输出:
GC就是Young GC,年轻代的GC
-XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags -XX:+PrintGC
-XX:+UseConcMarkSweepGC 使用CMS,观察CMS的GC
输出相比默认垃圾回收期PS+PO会更为详尽,
并且多了CMS Initial Mark
GC日志格式
关于上图中的Times含义:在linux中的times代表:
Heap Dump的含义(Linux)
eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
后面的内存地址指的是,起始地址,使用空间结束地址,整体空间结束地址
年轻代的total = eden + 1个survivor
调优前的基础概念
- 吞吐量throughput:用户代码执行时间 /(用户代码执行时间 + 垃圾回收时间)
(可以理解为干正经事的时间占总时间的比例)
吞吐量越大,JVM花在GC上的时间越少 - 响应时间:STW越短,响应时间越好
这俩指标几乎是不可能兼得的,
想要更高的吞吐量,就是要GC总体占用更少的CPU时间,这样的话,一旦需要STW,会STW很久(典型代表:CMS);
想要更快的响应时间,就是要STW很短,需要有线程去不断的标记处理对象,但是这样的话,吞吐量势必会降低,因为GC占用更多的CPU时间了.
所谓调优,首先确定,追求啥?
吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量
问题:
吞吐量优先:科学计算/数据挖掘,一般选择PS + PO
响应时间优先:网站 GUI API (1.8 选择G1)
什么是调优
- 根据需求进行JVM规划和预调优
- 优化运行JVM环境(慢,卡顿,一般是GC的STW过长了)
- 解决JVM运行过程中出现的各种问题(CPU 内存使用过高告警,OOM)
并发理解:
- QPS
- TPS
淘宝双11并发历年最高54万,据说12306并发比淘宝更高,号称上百万
调优,从规划开始
- 调优,从业务场景开始,没有业务场景的调优都是耍流氓
- 无监控(压力测试,能看到结果),不调优
- 步骤:
- 熟悉业务场景,选择优化的维度(没有最好的垃圾回收器,只有最合适的垃圾回收器)
- 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
- 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
- 选择回收器组合
- 计算内存需求(经验值,不一定是越大越好, 有的从1.5G升到16G甚至还慢了很多)
- 选定CPU(越高越好)
- 设定年代大小、升级年龄
- 设定日志参数
- -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
使用5个GC日志文件,每个文件最大20M,超过5个时最新的文件会把最老的覆盖掉 - 或者每天产生一个日志文件
- -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5
- 观察日志情况
-
案例1:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?
-
案例2:12306遭遇春节大规模抢票应该如何支撑?(架构问题)
-
怎么得到一个事务会消耗多少内存?
优化环境
-
有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了
- 为什么原网站慢?
很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢 - 为什么会更卡顿?
内存越大,FGC时间越长 - 咋办?
PS -> PN + CMS 或者 G1
- 为什么原网站慢?
-
系统CPU经常100%,如何调优?(面试高频)
CPU100%那么一定有线程在占用系统资源,- 找出哪个进程cpu高(top)
- 该进程中的哪个线程cpu高(top -Hp)
- 导出该线程的堆栈 (jstack)
- 查找哪个方法(栈帧)消耗时间 (jstack)
工作线程占比高 | 垃圾回收线程占比高
-
系统内存飙高,如何查找问题?(面试高频)
- 导出堆内存 (jmap)
- 分析 (jhat jvisualvm mat jprofiler … )
-
如何监控JVM
- jstat jvisualvm jprofiler arthas top…