抛出异常–缓慢而丑陋
這篇文章是關(guān)于歷史經(jīng)驗以及最近應(yīng)用的性能優(yōu)化技術(shù)的。 幾年前,我在特定的應(yīng)用程序中發(fā)誓,我不得不發(fā)現(xiàn)隱藏在真正聰明的工程“技術(shù)”之下的無證行為。
它是一個典型的用于發(fā)票的單片Java EE應(yīng)用程序。 最好忘記確切的代碼,但是我記得開發(fā)人員已經(jīng)找到了一種真正聰明的方法來控制業(yè)務(wù)流程。
流程的一部分通常是無休止的if-then-else混亂,但使事情更加“令人興奮”的是,這些檢查的一些隨機元素被埋入了自定義java.lang.RuntimeException處理機制中。 因此,您可能具有類似于以下內(nèi)容的代碼:
if (invoice.overdue()) {if (invoice.getCustomer().isKeyCustomer())throw new InvoiceOverdueException(InvoiceOverdueException.KEY_CUSTOMER);elsedoSomething(); } else {if (invoice.getDueAmount() > BIG_AMOUNT)if (invoice.getCustomer().isKeyCustomer())//be silentelsethrow new InvoiceExceededException(invoice.getDueAmount()); }并非像上述那樣簡短易懂的塊,而是在整個應(yīng)用程序中散布了數(shù)千行代碼。
我想你可能同意我的觀點,這是使自己不可或缺的一種好方法。 有人會以一種瘋狂的方式來理解應(yīng)用程序為什么會如此。
我回想起最近的Plumbr優(yōu)化任務(wù)帶來的經(jīng)驗。 我想說我們的代碼沒有使用前面案例描述的異常,但是不幸的是,這并非完全正確。 一個特定的方法仍然在代碼的常規(guī)流程中構(gòu)造并拋出RuntimeException 。 由于這個特定模塊的性能異常,我只發(fā)現(xiàn)了這個孤獨的反派。
通常,僅在遇到意外問題時才會引發(fā)異常。 因此,我們不希望每個線程每秒拋出數(shù)千個異常。 但是像我一樣,您可能會發(fā)現(xiàn)一種對異常事件使用異常的方法。
我之所以只找到罪魁禍首,是因為這是特定圖形遍歷算法中經(jīng)常使用的代碼塊,因此從中擠出最后一毫秒至關(guān)重要。 立即刪除異常處理使此代碼塊的完成速度提高了100倍以上。
這可能使您想知道–為什么異常處理速度很慢? 最慢的部分與構(gòu)造異常有關(guān)。 或者,更確切地說,是java.lang.Throwable的任何子類。
如果您還記得的話,所有構(gòu)造函數(shù)都會通過調(diào)用super()來調(diào)用對超類默認構(gòu)造函數(shù)的調(diào)用。 如果您未自行指定此調(diào)用,則編譯器會友好地將其添加到字節(jié)碼本身中。 無論如何,當查看java.lang.Throwable源代碼時,您會看到答案盯著您:
public Throwable() {fillInStackTrace();}public synchronized Throwable fillInStackTrace() {if (stackTrace != null ||backtrace != null /* Out of protocol state */ ) {fillInStackTrace(0);stackTrace = UNASSIGNED_STACK;}return this;}private native Throwable fillInStackTrace(int dummy);因此,每次創(chuàng)建新的Throwable()時,最終都會通過本機調(diào)用填充整個堆棧跟蹤。 如果您不認為這很慢,請執(zhí)行以下jmh微基準測試,以驗證創(chuàng)建異常的費用比構(gòu)造常規(guī)對象的費用高數(shù)百倍:
@BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public class NewExceptionTest {@GenerateMicroBenchmarkpublic Object baseline() {return new Object();}@GenerateMicroBenchmarkpublic Object exceptional() {return new RuntimeException();} }Benchmark Mode Thr Cnt Sec Mean Mean error Units j.NewExceptionTest.baseline avgt 1 5 5 3.275 0.029 nsec/op j.NewExceptionTest.exceptional avgt 1 5 5 1329.266 8.675 nsec/op 總而言之,在特殊情況下,名稱應(yīng)表示例外。 如果您開始濫用該概念,那么您要么使代碼不可讀,要么開始遭受性能問題的困擾。 至少,我保證您會從中獲得大量的負面因果報應(yīng)。
翻譯自: https://www.javacodegeeks.com/2013/08/throwing-exceptions-slow-and-ugly.html
總結(jié)
以上是生活随笔為你收集整理的抛出异常–缓慢而丑陋的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国寿周周盈收益怎么不更新?
- 下一篇: 安全地创建和存储密码