2014-09-30 27 views
4

我們最近應用了幾乎所有應用程序模塊/組件(大約50個項目)都使用的緩存解決方案。爲了更好地理解哪些緩存操作在不同的系統「位置」上執行,我們爲當前執行的緩存操作(包括堆棧跟蹤)添加了日誌記錄,以準確知道觸發緩存操作的內容。訪問性能良好的堆棧跟蹤?

我們當前的方法如下所示:我們從新的Throwable()中獲取堆棧跟蹤,過濾不相關的行並記錄剩餘的堆棧跟蹤。儘管創建一個新的例外來遺憾地登錄並不便宜。由於我們不直接使用緩存,而是通過休眠來找到哪個調用者觸發操作而不訪問堆棧跟蹤並不那麼容易。我的問題是:是否有更高性能的解決方案來訪問當前的堆棧跟蹤,然後Throwable()。getStackTrace或Thread.currentThread()。getStackTrace()?

+3

「創建一個新的例外遺憾日誌是沒有便宜的操作雖然」 - 其實我想不出任何其他的操作,可以比這更貴。你不能用它的源代碼來測試休眠嗎? – Leo 2014-09-30 08:46:01

+0

是的,我想我們可以。我們也討論過這個問題,但我們希望先用這個不費腦筋的解決方案來嘗試。 – u6f6o 2014-09-30 08:55:50

回答

4

Thread.currentThread().getStackTrace()與@apangin指出的基本相同,但如果避免創建Throwable,將來可能會更快。

但是,您可能會發現子採樣會爲您提供所需的改進。記錄每次訪問,而不是記錄每次訪問。如果您每記錄10次訪問就可以減少高達90%的開銷,並且如果訪問次數很多,它將幾乎一樣準確。

另一個選擇是使用像YourKit這樣的分析器,它可以更有效地做到這一點。這可以告訴你方法和堆棧跟蹤有多少不同的調用方(通常每10秒記錄一次)

+0

Thx,針對子採樣建議!沒想到這一點。 – u6f6o 2014-09-30 09:02:18

+6

爲什麼你認爲'Thread.currentThread()。getStackTrace()'更快?看看[sources](http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/1ed30c084e3d/src/share/classes/java/lang/Thread.java#l1566):它是實現爲新的異常()。getStackTrace()' – apangin 2014-09-30 10:39:48

+0

@apangin +10如果我可以。謝謝。 – 2014-09-30 10:49:41

0

您還可以做些什麼來實現java agent。這將正確地測試你想要跟蹤的代碼片段。

Here you will find how to start

+0

如何避免需要堆棧跟蹤? – 2014-09-30 10:50:22

+0

這個想法是,使用工具接口,他可以使用方法入口事件來獲取框架位置和遍歷堆棧。 – 2014-09-30 14:38:40

7

實際上得到一個異常堆棧跟蹤是沒有這樣慢:

  • 只有10%時間都花在收集回溯 - 這是在Throwable()構造函數中完成;
  • 其他90%時間花費從內部格式轉換回溯到可讀StackTraceElement[]陣列 - 這在getStackTrace()完成。

這意味着,如果你不需要同步處理堆棧跟蹤,你可以調用new Exception()(這是或多或少快速操作),然後調用e.getStackTrace()在另一個線程後或異步。

此外,有時(如在你的情況),完整的堆棧跟蹤是不需要的。您可以跳過一些堆棧幀並僅解碼您感興趣的那些。魔術sun.misc.SharedSectets類將有所幫助。

E.g.只得到幀2到5,使用

Exception e = new Exception(); 
int depth = Math.min(5, SharedSecrets.getJavaLangAccess().getStackTraceDepth(e)); 

for (int frame = 2; frame < depth; frame++) { 
    StackTraceElement elem = SharedSecrets.getJavaLangAccess().getStackTraceElement(e, frame); 
    System.out.println(elem); 
} 
+0

值得注意的是,sun。*軟件包僅供內部使用,不應被「最終」用戶使用。除此之外,這意味着,在創建一個新的java版本時,保留太陽的程度要小得多。*軟件包向後兼容而不是官方公開的軟件包。 – reallynice 2016-10-12 10:45:52

+2

@reallynice對。 'SharedSecrets'適用於Java 8.它不適用於Java 9,但是,有新的標準[StackWalker API](http://download.java.net/java/jdk9/docs/api/java/lang /StackWalker.html)用於Java 9及更高版本。 – apangin 2016-10-12 11:50:39