Java 为什么热点编译日志时间与ManagementFactory.getRuntimeMXBean().getUptime()不同?
当我用参数启动JVM时Java 为什么热点编译日志时间与ManagementFactory.getRuntimeMXBean().getUptime()不同?,java,jvm,benchmarking,jvm-hotspot,Java,Jvm,Benchmarking,Jvm Hotspot,当我用参数启动JVM时 -XX:+PrintCompilation 输出如下: 60 1 java.lang.String::hashCode (55 bytes) 74 2 sun.nio.cs.UTF_8$Encoder::encode (361 bytes) [62:log from Java code] 103 5 benchmark.AbstractBenchmarkST::benchma
-XX:+PrintCompilation
输出如下:
60 1 java.lang.String::hashCode (55 bytes)
74 2 sun.nio.cs.UTF_8$Encoder::encode (361 bytes)
[62:log from Java code]
103 5 benchmark.AbstractBenchmarkST::benchmark (82 bytes)
[62:log from Java code]
第一列是打印日志时的时间戳(毫秒),我想将此时间戳与ManagementFactory.getRuntimeMXBean().getUptime()返回的值进行比较:
或
但我的结果是这样的:
60 1 java.lang.String::hashCode (55 bytes)
74 2 sun.nio.cs.UTF_8$Encoder::encode (361 bytes)
[62:log from Java code]
103 5 benchmark.AbstractBenchmarkST::benchmark (82 bytes)
[62:log from Java code]
它们之间似乎相差约40毫秒,这使得两个时间戳无法相比。有什么办法解决这个问题吗?简短回答
热点JIT编译日志第一列中打印的时间(使用“-XX:+PrintCompilation”参数启动JVM时)的持续时间恒定,大于ManagementFactory.getRuntimeMXBean().getUptime()返回的时间(假定getUptime与打印编译日志的时间大致相同)
这至少适用于在Windows 7下运行的JDK 7,并且可以通过使用“-XX:+printcomilation”执行以下代码来轻松验证:
结果应该如下所示:
60 1 java.lang.String::hashCode (55 bytes)
74 2 sun.nio.cs.UTF_8$Encoder::encode (361 bytes)
[62:log from Java code]
103 5 benchmark.AbstractBenchmarkST::benchmark (82 bytes)
[62:log from Java code]
JVM正常运行时间:43
尽管ManagementFactory.getRuntimeMXBean().getUptime()是在打印的JIT编译之后调用的,但返回的时间似乎指向了以前的调用
似乎它们之间有40毫秒左右的差异,这种差异使其无法比拟。你知道怎么处理吗
由于时差是恒定的,并且在运行JVM的过程中不会发生变化,所以只要考虑到时差,就应该能够比较时间
长答案
“-XX:+printcomilation”JVM参数几乎没有文档记录,人们只能猜测,第一列表示与JVM启动相关的时间戳。但是,如果看一下HotSpot编译器的源代码,就会发现PrintCompilation打印的时间和ManagementFactory.getRuntimeMXBean().getStartTime()返回的时间引用了两个完全不同的时间戳,这两个时间戳都是在JVM启动期间初始化的
在调用以下对象时打印编译日志:
st->time_stamp()在ostream.cpp中实现,并引用使用os::Expressed_counter()返回的时间初始化的:
:
:
在以下过程中,通过调用os::init()依次初始化os::eaperd_counter():
另一方面,java方法ManagementFactory.getRuntimeMXBean().getStartTime()在以下情况中引用本机方法:
它在中实现,并从JmmInterface常量JMM_JVM_INIT_DONE_time_MS返回时间:
:
在已调用os::init()的一段时间后,在JVM启动期间初始化:
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
[...]
os::init();
[...]
// record VM initialization completion time
Management::record_vm_init_completed();
[...]
}
因此,JIT编译日志打印的时间与ManagementFactory.getRuntimeMXBean().getStartTime()返回的时间不同。哪段代码写入了两次?
void outputStream::stamp() {
if (! _stamp.is_updated()) {
_stamp.update(); // start at 0 on first call to stamp()
}
[...]
}
void TimeStamp::update() {
update_to(os::elapsed_counter());
}
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
[...]
os::init();
[...]
}
public native long getStartupTime();
case JMM_JVM_INIT_DONE_TIME_MS:
return Management::vm_init_done_time();
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
[...]
os::init();
[...]
// record VM initialization completion time
Management::record_vm_init_completed();
[...]
}