常见系统优化面试题
1. 慢、卡顿、怎么优化?
有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了
1. 为什么原网站慢?
很多用户浏览数据,很多数据load到内存,内存不足,频繁FullGC,STW长,响应时间变慢
2. 为什么会更卡顿?
内存越大,FGC需要扫描处理的空间越大,STW时间越长
3. 怎么解决?
把默认的PS + PO 调整成 PN + CMS 或者 G1
2. 系统CPU经常100%,如何调优?(面试高频)
CPU经常100%,那么一定有线程在占用系统资源,把它就出来分析问题
1. 找出哪个进程cpu高 :top (jps)
2. 该进程中哪个线程cpu高:top -Hp + 进程号 (一般超过80%就是比较高的 ,)
3. 查看该线程的堆栈:jstack + 线程号 (jstack pid > pid.log) 将线程栈Dump到日志文件中,由于线程快照中的线程id 都是 16进制存放的,所以查找nid = 线程id的16进制 的 地方.为了更直观的查看线程的状态,可以将快照信息上传到专门分享的平台上:http://fastthread.io/
4. 查找哪个方法(栈帧)消耗时间(jstack)
通过第3步就可以区分导致CPU过高的原因具体是Full GC次数过多还是代码中有比较耗时的计算了。
1. 如果是Full GC次数过多
1. 那么通过jstack得到的线程信息会是类似于VMThread之类的线程。这里我们基本上可以确定,当前系统缓慢的原因主要是垃圾回收过于频繁,导致GC停顿时间较长。我们可以通过如下命令查看GC的情况 jstat -gcutil ,如果FCG的数量很大,并且还在不断增长,从而进一步证实了是由于内存溢出导致的系统缓慢。
2. 上一步确认了内存溢出后,可以dump出内存日志,然后通过eclipse的mat工具进行查看,其展示的一个对象树结构,经过mat工具分享后,基本就能确定内存中主要是哪个对象比较消耗内存,然后找到该对象的创建位置,进行处理即可。
总结来说,对于FGC 次数过多,主要有一下两种原因
1. 代码中一次获取了大量的对象,导致内存溢出,此时可以通过eclipse的mat工具查看内存中有哪些对象比较多;
2. 内存占用不高,但Full GC次数还是比较多,此时可能是显示的调用了System.gc() 导致的
5. 如果是代码中有比较耗时的计算,那么我们得到的就是一个线程的具体堆栈信息。
如下是一个代码中有比较耗时的计算,导致CPU过高的线程信息, 这里可以看到,在请求UserController的时候,由于该Controller进行了一个比较耗时的调用,导致该线程的CPU一直处于100%。
我们可以根据堆栈信息,直接定位到UserController的34行,查看代码中具体是什么原因导致计算量如此之高。
参考文章:https://blog.csdn.net/g6U8W7p06dCO99fQ3/article/details/103415286;
https://www.cnblogs.com/technologykai/articles/10759561.html
3. 系统内存飙高,如何查找问题?(面试高频)
导出堆转储快照文件进行离线问题分析:jmap -dump
对堆内存文件进行问题分析 (jhat jvisualvm mat jprofiler … )
或者使用在线排查工具:如arthas
一般是运维团队首先受到报警信息(CPU飙高、Memory爆满)
top命令观察到问题:内存不断增长 CPU占用率居高不下
top -Hp 观察进程中的线程,哪个线程CPU和内存占比高
jps定位具体线程,jstack定位线程状态,重点关注WAITING BLOCKED
为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称?就是为了在线程池发生问题时,能够快速定位到在哪里发生的问题,尽快进行排查
怎么样自定义线程池里的线程名称?(多线程中,自定义ThreadFactory)
4. 如何定位OOM?
如果面试官问你是怎么定位OOM问题?——回答使用命令行工具
常用命令行工具:
1. jmap - histo XX| head -20
这个命令可以在线查看哪些对象出现的问题。如上面就是查找占用率对象的前二十,一般就能查找出现问题的对象
2. jmap -dump:导出堆文件,对文件进行问题分析、排查(会影响系统运行,慎用!!!)
jdump执行期间会对进程产生很大影响,线上系统内存特别大就会造成卡顿(电商不适合),解决办法(面试如何回答):
设定了参数HeapDump,OOM的时候会自动产生堆转储文件
有很多服务器备份(高可用),停掉这台服务器对其他服务器不影响
3. 然后使用MAT / jhat /jvisualvm 进行dump文件分析
4. 最后根据堆dump文件离线分析,找到代码的问题
GC案例-回答OOM如何产生?
1. 硬件升级系统反而卡顿的问题
有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低
为什么原网站慢?
很多用户浏览数据,很多数据load到内存,到最后堆内存不足,频繁FullGC
优化硬件配置之后,为什么会更卡顿?
由于堆内存变大,一旦老年代满了需要触发FullGC,而由于内存变大,FullGC造成的STW时间更长,造成的现象就是用户使用的卡顿更加严重
怎么优化?
把默认的垃圾收集器组合PS + PO 调整成 PN + CMS 或者 G1
2. 线程池不当运用产生OOM问题(能说)
由于在线程池的过程中,很容易出现其中某些线程在使用的时候,出现内存逃逸,无效对象一直被占用,产生巨量的无效对象,就会造成频繁GC;或者使用某些需要加锁,加锁对象一直不释放,导致大量的线程在循环等待,也会导致系统卡顿,比如CPU飙高或者不断GC
解决办法?
使用在线排查工具如arthas,或者使用jmap -dump导出堆内存文件,或者其他的 jmap 命令定位对象、线程的异常情况
3. http-header-size过大问题
在tomcat中通过参数可以调整http-header-size大小,默认的是4096,每来一个http请求,就会申请4096个字节,你可以说是不知道哪一个同事把这个参数调整的非常大,一旦申请量过大,就会导致内存溢出
解决办法?
通过命令行jmap查看哪些对象占用内存过大,通过日志查看到是Http11OutputBuffer对象占用内存特别大,请求过多导致很多Http11OutputBuffer对象产生,导致OOM,查找相关配置参数发现谁改动了配置
GC常用参数
1. 常用垃圾回收器组合设定参数(1.8)
1. -XX:+UseSerialGC = Serial New(DefNew)+Serial Old
小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和JDK版本自动选择收集器
JDK1.8及以前:PS + PO;JDK1.9:G1
2. -XX:+UseParNewGC = ParNew + SerialOld
这个组合已经很少用(在某些版本中已经废弃)
3. -XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old
使用PN + CMS + Serial Old;现在很少使用CMS了,因为G1完虐CMS,直接使用G1即可
4. -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】
5. -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
6. -XX:+UseG1GC = G1
Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC
7. java -XX:+PrintCommandLineFlags -version
通过GC的日志来分辨
8.Linux下1.8版本默认的垃圾回收器到底是什么?
1. 1.8.0_181 默认(看不出来)Copy MarkCompact
2. 1.8.0_222 默认 PS + PO
了解JVM常用命令行参数
1. JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
2. HotSpot参数分类
标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
3. 区分概念: 内存泄漏memory leak ,内存溢出out of memory
内存泄漏是指有些无用的对象,并不能被回收,仍然占用内存。
内存泄漏不一定内存溢出,如果垃圾回收一直都能保证有足够的内存空间,内存泄漏也无所谓,但是当大量内存泄漏的时候,就可能会造成内存溢出了。
GC日志详解
每种垃圾回收器的日志格式是不同的!
PS日志格式
JVM调优
基础概念
1. 吞吐量
用户代码执行时间:(用户代码执行时间 + 代码执行时间)
比例越大说明程序用来执行业务代码的时间越大,有效时间越高,吞吐量越大越好
2. 响应时间
STW越短,系统越顺畅、不卡顿,响应时间越好
3. 什么是调优?
所谓调优,首先确定需要向什么方向调优,也就是追求什么?**吞吐量优先,还是响应时间优先?**还是在满足一定的响应时间的情况下,要求达到多大的吞吐量?…
追求吞吐量:科学计算、数据挖掘(爬虫)、thrput等吞吐量优先的一般选择收集器组合:(PS + PO)
追求响应时间:电商网站、调用API第三方接口等需要响应时间优先的选择收集器组合:(PN + CMS、G1)
JVM 故障处理工具
1. jps :虚拟机进程状况工具
JPS:JVM Process Status Tool,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(main方法所在的类)名称以及进程的唯一ID
2. jstat:虚拟机统计信息监视工具
jstat:用于监视虚拟机各种运行状态信息的命令行工具
3. jinfo:JVM配置信息工具
jinfo的作用是实时查看和调整虚拟机各项参数
4. jmap:java内存映像工具(重要)
jmap(Memory Map for Java)命令用于生成堆转储快照文件(一般称为heapdump或dump文件),通过对dump文件的分析,我们可以发现出现的问题所在
5. jhat:JVM堆转储快照分析工具
JDK提供jhat命令与jmap来搭配使用,来分析jmap命令dump出的堆转储快照
6. jstack:JVM堆栈跟踪工具
jstack命令用于生成虚拟机当前时刻的线程快照(一般称为 javacore 文件)
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是为了定位线程长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的原因
排查线程阻塞、CPU飙高的常用命令
可视化故障处理工具
JDK中除了大量的命令行工具外,还提供了功能集成度更高的可视化工具,使用这些可视化工具能够以更加简洁明了的方式进行进程故障诊断和调试工作。
这类工具主要有:JConsole、VisualVM和 JMC ,除此之外阿里的 arthas 在线排查工具也很好用
1. JConsole: JVM监视与管理控制台
JConsole是一款可视化监视、管理工具,可以对系统进行信息收和参数动态调整:
1. 内存监控:相当于可视化的 jstate 命令工具,用于监视被收集器管理的JVM内存的变化趋势
2. 线程监控:相当于可视化的 jstack 命令工具,用于监视出现异常的线程停顿(如死循环、锁等待、请求外部资源等)
2. VisualVM:多合—故障处理工具
Visual VM是功能最强大的运行监视和故障处理程序之一,是官方主力发展的JVM故障处理工具
Visual VM有一个很大的优点:不需要被监视的程序基于特殊Agent去运行,因此它的通用性很强,对应用程序实际性能的影响也较小,因此它可以直接运行在生成环境中,这是其他工具不能媲美的
3. arthas在线排查工具
在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。
对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。所以需要使用arthas在线排查工具是阿里研发,很好用
附录–常见面试题
1. -XX:MaxTenuringThreshold控制的是什么?
A: 对象升入老年代的年龄
B: 老年代触发FGC时的内存垃圾比例
答: A , -XX:MaxTenuringThreshold设置的是年龄阈值,默认15(对象被复制的次数)
2. 生产环境中,倾向于将最大堆内存和最小堆内存设置为:(为什么?)
A: 相同 B:不同
答: A
3. JDK1.8默认的垃圾回收器是:
A: ParNew + CMS
B: G1
C: PS + ParallelOld
D: 以上都不是
答:C
4. 什么是响应时间优先?
答:STW越短,系统越顺畅、不卡顿,响应时间越好
5. 什么是吞吐量优先?
答: 用户代码执行时间:(用户代码执行时间 + 代码执行时间)
比例越大说明程序用来执行业务代码的时间越大,有效时间越高,吞吐量越大越好
6. ParNew和PS的区别是什么?
答: ParNew 能和CMS配合使用,ps不行
7. ParNew和ParallelOld的区别是什么?(年代不同,算法不同)
8. 长时间计算的场景应该选择:A:停顿时间 B: 吞吐量
答:B
9. 大规模电商网站应该选择:A:停顿时间 B: 吞吐量
答:A
10. HotSpot的垃圾收集器最常用有哪些?
11. 常见的HotSpot垃圾收集器组合有哪些?
12. JDK1.7 1.8 1.9的默认垃圾回收器是什么?如何查看?
查看JDK不同版本使用的垃圾回收器,设置参数:-XX:+PrintCommandLineFlags
JDK 1.8 默认采用的是ParallelGC ,老年代默认就是Parallel old 了,JDK 1.9默认采用的就是 G1 垃圾回收器了
13. 所谓调优,到底是在调什么?
答:1. 根据需求进行JVM规划和预调优
2. 优化运行JVM运行环境(慢,卡顿)
3. 解决JVM运行过程中出现的各种问题(JVM调优主要就是为了解决OOM问题)
13. 如果采用PS + ParrallelOld组合,怎么做才能让系统基本不产生FGC
14. 如果采用ParNew + CMS组合,怎样做才能够让系统基本不产生FGC
1.加大JVM内存
2.加大Young的比例
3.提高Y-O的年龄
4.提高S区比例
5.避免代码内存泄漏
15. G1是否分代?G1垃圾回收器会产生FGC吗?
16. 如果G1产生FGC,你应该做什么?
1. 扩内存
2. 提高CPU性能(回收的快,业务逻辑产生对象的速度固定,垃圾回收越快,内存空间越大)
3. 降低MixedGC触发的阈值,让MixedGC提早发生(默认是45%)
17. 问:生产环境中能够随随便便的dump吗?
小堆影响不大,大堆会有服务暂停或卡顿(加live可以缓解),dump前会有FGC
18. 问:常见的OOM问题有哪些?
栈 堆 MethodArea 直接内存
参考文章:
https://blog.csdn.net/qq_42583242/article/details/107827631