本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试。
记录日期:2022.1.3
大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习。
jvm调优内容建议手操以下,记忆深刻一点。
现在这里汇总一下可能会经常用到的JVM参数:
这里以IDEA为例:
调优工具不是要讲的重点,这些理应都应该知道,就不详细说了。
博客参考链接:Java系列笔记(4) - JVM监控与调优
jps、jstat、jhat、jinfo、jstack、jmap、jconsole、jvisualvm。这里主要清楚下jstack 和 jvisualvm,这两个比较常用。
博客参考链接:Java常用命令(一) jps、jstack、jmap
jstack:java命令–jstack 工具
博客参考链接:JConsole可视化工具介绍
博客参考链接:java jvisualvm简要说明
jvisualvm可以监控内存泄露,跟踪垃圾回收,执行时内存、cpu分析,线程分析…
jvisualvm已经被集成在jdk1.6以上的版本中(不是jre)。自身运行需要最低jdk1.6版本,但是可以监控运行在jdk1.4以上版本的java程序。
cmd中打开直接输入”jvisualvm“。
打开jvisualvm界面。
通过可视化监控jvm信息。
使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
这里就要关注几个指标:
使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化。
调优可以依赖、参考的数据有系统运行日志、堆栈错误信息、gc日志、线程快照、堆转储快照等。
“java.lang.OutOfMemoryError: Java heap space”
可以判断是堆内存溢出;根据“java.lang.StackOverflowError”
可以判断是栈溢出;根据“java.lang.OutOfMemoryError: PermGen space”
可以判断是方法区溢出等。-XX:+PrintGCDetails
和 -Xloggc:/data/jvm/gc.log
可以在程序运行时把gc的详细过程记录下来,或者直接配置“-verbose:gc”
参数把gc日志打印到控制台,通过记录的gc日志可以分析每块内存区域gc的频率、时间等,从而发现问题,进行有针对性的优化。“jstack pid”
命令,可以dump出当前进程中线程的快照信息,更详细的使用和分析网上有很多例,这篇文章写到这里已经很长了就不过多叙述了。“-XX:+HeapDumpOnOutOfMemory”
和 “-XX:HeapDumpPath=/data/jvm/dumpfile.hprof”
,当程序发生内存溢出时,把当时的内存快照以文件形式进行转储(也可以直接用jmap命令转储程序运行时任意时刻的内存快照),事后对当时的内存使用情况进行分析。如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;
如果GC时间超过1-3秒,或者频繁GC,则必须优化。
注:如果满足下面的指标,则一般不需要进行GC优化:
- Minor GC执行时间不到50ms;
- Minor GC执行不频繁,约10秒一次;
- Full GC执行时间不到1s;
- Full GC执行频率不算频繁,不低于10分钟1次;
如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择。
针对不同的问题在不同层面提供优化方案:
JVM配置方面,一般情况可以先用默认配置(基本的一些初始参数可以保证一般的应用跑的比较稳定了),在测试中根据系统运行状况(会话并发情况、会话时间等),结合gc日志、内存监控、使用的垃圾收集器等进行合理的调整,当老年代内存过小时可能引起频繁Full GC,当内存过大时Full GC时间会特别长。
那么JVM的配置比如新生代、老年代应该配置多大最合适呢?答案是不一定,调优就是找答案的过程,物理内存一定的情况下,新生代设置越大,老年代就越小,Full GC频率就越高,但Full GC时间越短;相反新生代设置越小,老年代就越大,Full GC频率就越低,但每次Full GC消耗的时间越大。建议如下:
代码实现方面,性能出现问题比如程序等待、内存泄漏除了JVM配置可能存在问题,代码实现上也有很大关系:
通过不断的试验和试错,分析并找到最合适的参数。
如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪。
如果CPU和内存同时上涨,一般推测是程序的某个线程进入死循环,不停的分配内存导致。
参考博客链接:阿里程序员不小心把服务器CPU打到100%,淡定展示教科书排查过程
⼀般CPU100%疯狂GC,都是死循环或者产生大对象的问题。
先进入对应的服务器,⽤top -c
命令找出当前进程的运⾏列表。
按⼀下P
可以按照CPU使⽤率进⾏排序。
假如说,显示Java进程 PID
为 1234
的java进程消耗最⾼。
然后我们需要根据PID
查出CPU⾥⾯消耗最⾼的进程。
使⽤命令 top -Hp 1234
找出这个进程下⾯的线程,继续按P
排序。
假如说,该进程下的 2854
线程 CPU消耗最⾼。
我们要导出该进程的快照,看看该线程做了什么工作。
jstack -l 1234 > ./1234.stack
再⽤grep
查看⼀下线程在⽂件⾥做了什么,b26
是2854
线程的16进制。
cat 1234.stack |grep 'b26' -C 8
这样就可以通过快照具体定位问题。
一应用在性能测试过程中,发现内存占用率很高,Full GC频繁,使用sudo -u admin -H jmap -dump:format=b,file=文件名.hprof pid 来dump内存,生成dump文件,并使用Eclipse下的mat差距进行分析,发现:
从图中可以看出,这个线程存在问题,队列LinkedBlockingQueue所引用的大量对象并未释放,导致整个线程占用内存高达378m,此时通知开发人员进行代码优化,将相关对象释放掉即可。
这里参考了一篇文章,在前面有表明引用。
一般如果出现java.lang.OutOfMemoryError: GC overhead limit exceeded
。
一般都是代表为了释放很小的空间却耗费了太多的时间,其原因一般有两个:
如果是第一点,使用ps -ef |grep "java"
查看,发现该应用使用堆过小,则只需要改变堆中各区域的大小设置即可。
如果是第二点,则可通过进程快照,根据日志找出问题代码进行修改。
一个服务系统,经常出现卡顿,分析原因,可能是Full GC时间太长。
jstat -gcutil:
S0 S1 E O P YGC YGCT FGC FGCT GCT
12.16 0.00 5.18 63.78 20.32 54 2.047 5 6.946 8.993
分析上面的数据,发现Young GC执行了54次,耗时2.047秒,每次Young GC耗时37ms,在正常范围。
而Full GC执行了5次,耗时6.946秒,每次平均1.389s,数据显示出来的问题是:Full GC耗时较长。
分析该系统的是指发现,NewRatio=9,也就是说,新生代和老生代大小之比为1:9,这就是问题的原因:
优化的方法是调整NewRatio的值,调整到4,发现Full GC没有再发生,只有Young GC在执行,这就是把对象控制在新生代就清理掉,没有进入老年代。
这种做法对一些应用是很有用的,但并不是对所有应用都要这么做。
待补充。
待补充。