持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
前面一章讲解了关于编译阈值的内容,介绍了其用途和如何修改。同时也介绍了编译的部分原理,只有达到编译阈值才会触发编译,同时编译阈值会周期性减少,导致出现永远无法编译的温热代码,可以通过降低阈值的方式去优化。本章我们来学习如何找到这些温热代码,对其进行优化。
那些方法被编译了?
PrintCompilation 标志
首先我们通过jvm提供的标志,来看看有哪些方法会被编译,我们需要开启PrintCompilation
标志,此标志默认是关闭的:
[root@hecs-402944 ~]# jinfo -flag PrintCompilation 13577
-XX:-PrintCompilation
复制代码
这个标志无法通过jinfo进行动态开启,所以我们需要重新启动项目指定参数:
nohup java -XX:+PrintCompilation -jar weather-forecast-0.0.1-SNAPSHOT.jar >/dev/null &
复制代码
再次查看:
[root@hecs-402944 opt]# jinfo -flag PrintCompilation 21405
-XX:+PrintCompilation
复制代码
前面的文章讲到过,-
减号表示关闭,+
加号表示开启。
开启此标志,每次jvm编译一个方法,就会打印对应的日志信息:
如上所示只是部分编译内容。
其格式如下:
timestamp | compilation_id | attributes | tiered_level | method_name | size | deopt |
---|---|---|---|---|---|---|
编译完成时间,从0开始 | 编译的id,通常自增1,线程调度偶尔会乱序 | 代码编译的状态。有五种标志: 1)%:栈上替换编译(OSR) 2)s:同步方法 3)!:带异常处理的方法 4)b:阻塞模式时发生的编译,不会打印,后面文章会提到 5)n:分装本地方法的编译,为了便于调用本地方法 |
使用分层编译后才会打印,打印数字,表示分层编译级别 | 被编译方法名字,格式:ClassName:methodName | 编译后大小(字节) | 发生逆优化, made zombie 或 made not entrant |
关于表格的内容,后面会有文章单独去介绍。
jstat工具
如果你不想通过重启的方式去开启编译方法的检测,那么还可以使用jstat工具。
jstat提供两个参数去查看编译信息:
-
-compiler
[root@hecs-402944 opt]# jstat -compiler 11210 Compiled Failed Invalid Time FailedType FailedMethod 2898 1 0 4.73 1 java/net/URLClassLoader$1 run 复制代码
如上所示,看到参数分别是:编译完成数,编译失败数,错误数,编译类型,失败方法名。
如果你发现自己的某个方法运行很慢,可以通过此命令查看,是否是因为编译失败引起的。
-
-printconpilation
[root@hecs-402944 opt]# jstat -printcompilation 11210 3000 Compiled Size Type Method 2981 63 1 java/util/concurrent/locks/AbstractQueuedSynchronizer shouldParkAfterFailedAcquire 2985 21 1 java/nio/channels/spi/AbstractSelector isOpen 2987 36 1 java/util/concurrent/locks/AbstractQueuedSynchronizer acquireInterruptibly 2991 98 1 java/util/concurrent/ScheduledThreadPoolExecutor$DelayedWorkQueue siftUp 2993 24 1 java/util/concurrent/ThreadPoolExecutor$Worker tryRelease 2997 65 1 java/util/concurrent/ScheduledThreadPoolExecutor$ScheduledFutureTask setNextRunTime 复制代码
如上所示,查看最近哪些方法被编译了。每3000毫秒打印一次。