可讀的JVM GC時間戳

當我們診斷Java應用程序的問題時,能夠查到垃圾回收的狀況是非常有幫助的。一個基本的最基礎的方法是開啓垃圾回收日誌。

也許你已經知道了,如果我們把下面的參數加到java啓動命令行中,

-Xloggc:<file_name> –XX:+PrintGCDetails -XX:+PrintGCDateStamps

JVM就會將垃圾回收信息寫到-Xloggc設置的文件中。日誌格式如下:

2010-04-22T18:12:27.796+0200: 22.317: [GC 59030K->52906K(97244K), 0.0019061 secs]
2010-04-22T18:12:27.828+0200: 22.348: [GC 59114K->52749K(97244K), 0.0021595 secs]
2010-04-22T18:12:27.859+0200: 22.380: [GC 58957K->53335K(97244K), 0.0022615 secs]
2010-04-22T18:12:27.890+0200: 22.409: [GC 59543K->53385K(97244K), 0.0024157 secs]

加粗的部分顯示了垃圾回收時間的開始日期及時間。

不幸的是-XX:+PrintGCDateStamps參數只有Java 6u4及以後版本的JVM纔可用。所以,如果我們很不幸而且我們的應用程序跑在就版本的JVM上,我們就被迫使用,

-Xloggc:<file> –XX:+PrintGCDetails

這樣,得到的垃圾回收信息如下:

22.317: [GC 59030K->52906K(97244K), 0.0019061 secs]
22.348: [GC 59114K->52749K(97244K), 0.0021595 secs]
22.380: [GC 58957K->53335K(97244K), 0.0022615 secs]
22.409: [GC 59543K->53385K(97244K), 0.0024157 secs]

現在,加粗的數字表示從JVM啓動時間開始的秒間隔。

這種情況下就很難把GC事件和其他日誌文件中的信息關聯到一起了:(

有沒有簡單的辦法來處理gc日誌文件並從秒間隔中關聯出日期和時間呢?看起來是可以的,但是秒間隔從什麼時候開始呢?換句話說,我們怎麼得知JVM的啓動日期和時間呢?

爲了使用最最基礎的方法,我們應該從同一個GC日誌文件中分析出日期和時間。這樣我們就要用到文件的屬性了。我們有如下不同的選擇:

Unix Windows
Access time Access time
Change time Creation time
Modify time Modify time

我們拋棄掉access time、cheng time及creation time,因爲他們不是在所有平臺上都可用的。這樣我們只剩下修改時間(modify time),表示文件最後一次修改的時間。

在Windows上,當文件被拷貝到其他地方時,修改時間是保持不變的。但是當我們在Unix上拷貝GC日誌文件時,我們需要使用-p選項來保持時間戳屬性

GC日誌文件的最後修改時間應該和日誌文件中最後一個記錄的GC時間的時間戳保持一致。好吧,更精確點,由於日誌行是在GC執行時一點一點寫的,最後修改時間應該是確切等於最後的秒間隔加上GC的執行時間。

22.409: [GC 59543K->53385K(97244K), 0.0024157 secs]


在我們的方法中由於不需要精確時間,我們拋棄執行時間,進而得到每次垃圾回收時間發生的粗略時間。然而,我們必須注意在大的heap中,有時間GC的執行時間可以長達幾秒。

當我們最近在一個客戶那裏體驗這個方案時,我們需要快速開發一個簡單的輕便的腳本,所以就選擇Python來實現這個功能。你已經知道了我們不僅僅用Java吧。大笑

  1. #!/usr/bin/env python  
  2.    
  3. import sys, os, datetime  
  4.    
  5. # true if string is a positive float  
  6. def validSeconds(str_sec):  
  7.     try:  
  8.         return 0 < float(str_sec)  
  9.     except ValueError:  
  10.         return False  
  11.    
  12. # show usage                  
  13. if len(sys.argv) < 2:  
  14.     print "Usage: %s <gc.log>" % (sys.argv[0])  
  15.     sys.exit(1)  
  16.    
  17. file_str = sys.argv[1]  
  18. lastmod_date = datetime.datetime.fromtimestamp(os.path.getmtime(file_str))  
  19.    
  20. file = open(file_str, 'r')  
  21. lines = file.readlines()  
  22. file.close()  
  23.    
  24. # get last elapsed time  
  25. for line in reversed(lines):  
  26.     parts = line.split(':')  
  27.     if validSeconds(parts[0]):  
  28.         break  
  29.    
  30. # calculate start time  
  31. start_date = lastmod_date - datetime.timedelta(seconds=float(parts[0]))  
  32.    
  33. # print file prepending human readable time where appropiate    
  34. for line in lines:  
  35.     parts = line.split(':')  
  36.     if not validSeconds(parts[0]):  
  37.         print line.rstrip()  
  38.         continue  
  39.     line_date = start_date + datetime.timedelta(seconds=float(parts[0]))  
  40.     print "%s: %s" % (line_date.isoformat(), line.rstrip())  

這個腳本的輸出可以重定向到另一個文件中,在哪裏可以得到:

2010-04-22T18:12:27.796375: 22.317: [GC 59030K->52906K(97244K), 0.0019061 secs]
2010-04-22T18:12:27.828375: 22.348: [GC 59114K->52749K(97244K), 0.0021595 secs]
2010-04-22T18:12:27.859375: 22.380: [GC 58957K->53335K(97244K), 0.0022615 secs]
2010-04-22T18:12:27.890375: 22.409: [GC 59543K->53385K(97244K), 0.0024157 secs]


你可能注意到了日期的格式並不是和-XX:+PrintGCDateStamps參數100%的一致。但這足以看出每個GC時間發生的時間。


原文:http://www.theserverlabs.com/blog/2010/05/26/human-readable-jvm-gc-timestamps/

PS:翻譯這篇blog主要是想和大家分享這個python腳本,非常的使用。在運維類似於Hadoop這樣的分佈式大集羣試,master的GC日誌是一定要打開,因爲各種各樣的問題都可能和GC有關。但由於某些原因,如JDK版本或歷史原因,可能配置了–XX:+PrintGCDetails而不是-XX:+PrintGCDateStamps,這樣就非常需要本文的腳本來轉換時間格式。當然最好是配上-XX:+PrintGCDateStamps參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章