陶炳哲 — MAY 12, 2015 在對OneAPM的客戶作技術支持時,咱們經常會看到不少客戶根本沒意識到的異常。在消除了這些異常以後,代碼運行速度與之前相比大幅提高。這讓咱們產生一種猜想,就是在代碼裏面使用異常會帶來顯著的性能開銷。由於異常是錯誤狀況處理的重要組成部分,摒棄是不太可能的,因此咱們須要衡量異常處理對於性能影響,咱們能夠經過一個實驗看看異常處理的對於性能的影響。 ##實驗編程
個人實驗基於一段隨機拋出異常的簡單代碼。從科學的角度,這並不是徹底準確的測量,同時我也並不瞭解 HotSpot
編譯器會對運行中的代碼作何動做。但不管如何,這段代碼應該可以讓咱們瞭解一些基本狀況。 服務器
結果頗有意思:拋出與捕獲異常的代價彷佛極低。在個人例子裏,大約是每一個異常 0.02 毫秒。除非你真的拋出太多異常(咱們指的是 10 萬次或者更多),不然這一點基本均可忽略。 儘管這些結果顯示出異常處理自己並不影響代碼性能,但卻並未解決下面這個問題:異常對性能的巨大影響該由誰負責?框架
##我明顯遺漏了什麼重要的問題。 從新想了一下,我意識到本身遺漏了異常處理的一個重要部分。我沒考慮到異常發生時你作了什麼。在多數狀況下你頗有可能不只僅是捕獲異常!而問題就在這裏:通常狀況下,你會試圖對問題進行補充,並讓應用在最終用戶那裏仍能發揮功能。因此我遺漏的就是:「」爲了處理異常而執行的補充代碼「」。按照補充代碼的不一樣,性能損失可能會變得至關顯著。在某些狀況下這可能意味着重試鏈接到服務器,在另外一些狀況下則可能意味着使用默認的回滾方案,而這種方案提供的解決辦法確定會帶來很是差勁的性能。對於咱們在不少狀況下看到的行爲,這彷佛給出了很好的解釋。性能
不過我卻不以爲分析到這裏已經萬事大吉,而是感到這裏還遺漏了別的什麼東西。設計
##Stack trace日誌
對此問題,我仍頗爲好奇,爲此監視了收集 strack trace 時狀況性能有何變化。code
常常發生的狀況應該是這樣的:記下異常及其棧軌跡,嘗試找出問題到底在哪。blog
爲此我修改了代碼,額外收集了異常的 strack trace 。這讓狀況顯著改變。對異常的 strack trace 的收集,其性能影響要比單純捕獲並拋出異常高出10倍。所以儘管 strack trace 有助於理解哪裏發生了問題(有可能還有助於理解爲什麼發生問題),但卻存在性能損失。 因爲咱們談論的並不是一條 strack trace,因此此處的影響每每很是之大。 多數狀況下,咱們都要在多個層次上拋出並捕獲異常。 咱們看一個簡單的例子: Web 服務客戶端鏈接到服務器。首先,Java 庫級別上存在一個鏈接失敗異常。此後會有框架級別上的客戶端失敗異常,再之後可能還會有應用層次上的業務邏輯調用失敗異常。到如今爲止,總共要蒐集三條strack trace。 多數狀況下,你都能從日誌文件或者應用輸出中看到這些 strack trace
,而寫入這些較長的 strack trace
每每也會也帶來性能影響。編譯器
##結論編譯
首先由於存在性能影響而把異常棄之不用並不是良策。異常有助於提供一種一致的方式來解決運行時問題,而且有助於寫出乾淨的代碼。但咱們應該對代碼中拋出的異常數量進行跟蹤,它們可能致使顯著的性能影響。因此 OneAPM 默認要對所拋出的異常進行跟蹤——在不少狀況下人們都會對代碼中發生的異常以及在解決這些異常時的性能損耗感到吃驚不已。 其次儘管使用異常頗有裨益,您也應避免捕獲過多的 strack
trace。異常應該是爲異常的狀況而設計的,使用時應該牢記這一原則。固然,萬一您不想聽從好的編程習慣,Java
語言就會讓您知道,那樣作可讓您的程序運行得更快,從而鼓勵您去那樣作。