2012-11-24 25 views
7

當我啓動JVM用參數爲什麼HotSpots編譯日誌時間與ManagementFactory.getRuntimeMXBean()。getUptime()不同?

-XX:+PrintCompilation 

輸出是這樣的:

60 1    java.lang.String::hashCode (55 bytes) 
74 2    sun.nio.cs.UTF_8$Encoder::encode (361 bytes) 

第一列在毫秒的時間戳,印刷記錄時,我想這個時間戳比較是得到由ManagementFactory.getRuntimeMXBean().getUptime()返回值:

long jvmUpTime = ManagementFactory.getRuntimeMXBean().getUptime(); 

long jvmStartTime = ManagementFactory.getRuntimeMXBean().getStartTime(); 

但我的結果是這樣的:

[62:log from Java code] 
103 5    benchmark.AbstractBenchmarkST::benchmark (82 bytes) 
[62:log from Java code] 

看來,他們之間有大約40毫秒的差異,這使得兩個時間戳無比。任何想法如何處理這個?

+3

哪個代碼寫了'[62:log ...'兩次? – fglez

回答

0

簡短回答

在熱點JIT編譯日誌中的第一列中打印的時間(與啓動JVM當「-XX:+ PrintCompilation」參數),是一個恆定的持續時間比所述時間大的由ManagementFactory.getRuntimeMXBean()。getUptime()返回(假設getUptime在編譯日誌打印的同時被調用)。

這至少是真實的JDK 7的Windows 7下運行,並可以通過執行以下代碼很容易地驗證「-XX:+ PrintCompilation」:

public static void main(String[] args) { 
    System.out.println("JVM uptime: " + ManagementFactory.getRuntimeMXBean().getUptime()); 
} 

結果應該是這個樣子:

77 1    java.lang.String::hashCode (55 bytes) 
79 2    java.lang.String::indexOf (70 bytes) 
80 3    java.lang.String::charAt (29 bytes) 
82 4    java.lang.String::lastIndexOf (52 bytes) 
82 5    java.lang.String::equals (81 bytes) 
82 6    java.lang.AbstractStringBuilder::ensureCapacityInternal (16 bytes) 
82 7    java.lang.String::indexOf (166 bytes) 
85 8  n  java.lang.System::arraycopy (native) (static) 

JVM運行時間:43

ë雖然ManagementFactory.getRuntimeMXBean()。getUptime()在打印的JIT編譯之後被調用,但返回的時間似乎指向先前的調用。

看來他們有大約40毫秒的差異,這種差異使得它無法比擬。任何想法如何處理這個?

由於時間差是不變的,在運行JVM時不應改變,所以只要考慮時間差,就應該能夠比較時間。

長的答案

的「-XX:+ PrintCompilation」 JVM說法很難證明,一個只能猜測,第一列表示相對於JVM的啓動時間戳。如果查看HotSpot編譯器的源代碼,可以明顯看出,PrintCompilation輸出的時間和ManagementFactory.getRuntimeMXBean()。getStartTime()返回的時間引用了兩個完全不同的時間戳,這兩個時間戳同時被初始化JVM的啓動。

編譯日誌在通話過程中獲得打印到CompileTask::print_compilation_impl

void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level, 
             bool is_osr_method, int osr_bci, bool is_blocking, 
             const char* msg, bool short_form) { 
    if (!short_form) { 
     st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp 
    } 
    st->print("%4d ", compile_id); // print compilation number 
    [...] 
} 

ST-> TIME_STAMP()在ostream.cpp實現的,是指獲取與由操作系統返回的時間初始化的TimeStamp :: elapsed_counter ():

ostream.cpp

void outputStream::stamp() { 
    if (! _stamp.is_updated()) { 
     _stamp.update(); // start at 0 on first call to stamp() 
    } 
    [...] 
} 

timer.cpp

void TimeStamp::update() { 
    update_to(os::elapsed_counter()); 
} 

OS :: elapsed_counter()又由呼叫初始化過程中獲取到OS ::的init()的startup of the JVM

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { 
    [...] 
    os::init(); 
    [...] 
} 

Java方法ManagementFactory.getRuntimeMXBean()getStartTime()。另一方面是指在VMManagementImpl.java本地方法:

public native long getStartupTime(); 

其在VMManagementImpl.c實現,並且從JmmInterface恆定JMM返回時間_JVM_INIT_DONE_TIME_MS:

management.cpp

case JMM_JVM_INIT_DONE_TIME_MS: 
     return Management::vm_init_done_time(); 

它被啓動了JVM的後相當長的一段時間OS ::初始化(中)初始化已經叫:

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { 
    [...] 
    os::init(); 
    [...] 
    // record VM initialization completion time 
    Management::record_vm_init_completed(); 
    [...] 
} 

因此,打印時間通過JIT編譯日誌不同於ManagementFactory.getRuntimeMXBean()。getStartTime()返回的時間。

相關問題