Discussions

News: Stop Handling Exceptions: Your Code Will Run Faster


  1. Recently I participated in  a discussion about the cost of exceptions.

    When working with customers we very often find a lot of exceptions they are not aware of. After removing these exceptions, the code runs significantly faster than before.

    "Getting the stack trace of an exception has a 10x higher impact on the performance than just catching and throwing them."

    This creates the assumption that using exceptions in your code comes with a significant performance overhead. The implication would be that you better avoid using exceptions.

    "While exception usage is good you should avoid capturing too many stack traces. In many cases they are not even necessary to understand the problem – especially if they cover a problem you already expect."

    As exceptions are an important construct for handling error situation, avoiding exceptions completely does not seem to be good solution. All in all this was reason enough to have a closer look at the costs of throwing exceptions.

    Read the full story

    Threaded Messages (28)

  2. As for performance...[ Go to top ]

    Avoid using Java/Python/Ruby/Scala and just use assembly. Seriously, guys all in all most of the time it does not really matter - most business apps hang on db operations anyway.

    Maybe it does actually matter for some small part of applications created but making general rule out of it... is just wrong.

  3. As for performance...[ Go to top ]

    Pawel,

    I agree that DB access is on of the main causes of application performance problems. This article discusses why you still should care about what happens in your exception handling code. Overlooked exceptions are in a lot of cases a problem in Java applications. 

     

    The title might be a bit catchy. It was not my orginial one ;-). 

  4. As for performance...[ Go to top ]

    Avoid using Java/Python/Ruby/Scala and just use assembly. Seriously, guys all in all most of the time it does not really matter - most business apps hang on db operations anyway.

    Maybe it does actually matter for some small part of applications created but making general rule out of it... is just wrong.

     

    Or start using Cocoa where most of the failures are handled by error codes returned in an integer passed by reference... actually, a hell (I speak due my own experience).

  5. It really strange when people talk about tiny piece of Java code in regards with performance when there are tuns of bottlenecks wither database calls or JSP rendering. Proper handling of Java exception is more helpful in compare with the negligible performance.

  6. Why are we worried about such micro tuning aspects when there are bigger issues to solve. With modern JVM and hardware exceptions are nothing. Also in most cases in the life of an application code is executed in the happy path about 85% of the time and 15% in exceptional path unless we are stupid enough to handle control flow by exceptions.

  7. An exceptionally bad start[ Go to top ]

    As much as I hate come to the rescue of a dynaTrace employee I need to point out some rather obvious items that seem completely lost here on those fixated with slow database response times (which need not always be the case).

    1. Applications today have huge call stack depths. Prior to Spring the typical max was +120 subsequently this has gone from 240 to 360 with no end in sight judging by the approach taken by rapid rails like frameworks.

    2. Applications today (other than Spring Pet/Travel Clinic apps) have a very large number of threads running concurrently and yes all probably down with deep call stacks making database queries or some other resource/service interaction.

    3. Getting the call stack is terribly, terribly, terribly,....expensive both in terms of cpu and object alloc (which we know what that leads to). This grows with each frame you add and by the way the JVM has to handle inlining issues (JRockit has slipped up on this previously).

    4. The default JVM/SDK behavior in constructing an exception is to fill the stack.

    5. Exceptions tend to be generated very deep in the call path/stack processing. 

    6. Some enterprise API's, JNDI, throw exceptions like they were cheap return values (i.e. no object bound here instead of null).

    7. The average developer loves to log exceptions with stack traces and then throw another exception which will be logged again further up the stack during unrolling. Logging libraries are notoriously badly designed/developed, under performing and IO intensive.

    8. GC is not execution aware in particular it does not know that one of your threads is currently doing a database operation that could potentially lock up the continued processing of other database operations being performed locally or remotely (in other JVM's).

    9. Most enterprise applications have some distributed coupling/coordination. More GC and your local problems suddenly spread like a virus across other JVM's. This has been an issue for many first generation data grid products.

    10. More (handling) code, potentially more bugs, definitely (relatively) slower, and just a bloody mess to maintain especially with all that pollution caused by your usage of logging which has in general an economic value of 0$.

    http://williamlouth.wordpress.com/2008/11/18/an-exceptionally-bad-start/

     

  8. An exceptionally bad start[ Go to top ]

    3. Getting the call stack is terribly, terribly, terribly,....expensive both in terms of cpu and object alloc (which we know what that leads to). This grows with each frame you add and by the way the JVM has to handle inlining issues (JRockit has slipped up on this previously).

    4. The default JVM/SDK behavior in constructing an exception is to fill the stack.

    I would like to disagree here. The stacktrace is only created if somebody requests it. (True, if you log it, you will request it) I've created a small test with JDK1.6: 

    Created a loop of 10000 iteration. Each iteration builds up a recursive stacktrace depth of 300 entries. Three variants:

    Exception + getStacktrace() : ~4400ms

    Exception w/o getStacktrace(): ~300ms

    No exception at all, return value checking : 6ms

    The same test with 3000 stacktrace elements yield:

    1) ~15sec

    2) 1300ms

    3) 70ms


    YES, exceptions are 2 magnitude slower (3 with stacktrace). In turn they will (can/should) make your code cleaner, because you omit the error-handling on the "happypath", also you don't need lot of plumbing code.

    6. Some enterprise API's, JNDI, throw exceptions like they were cheap return values (i.e. no object bound here instead of null).

    So true. Classloading throws exceptions a lot.

    7. The average developer loves to log exceptions with stack traces and then throw another exception which will be logged again further up the stack during unrolling. Logging libraries are notoriously badly designed/developed, under performing and IO intensive.

    Logging the exceptions and throwing further is a bad habbit. May be ok on system boundaries, there you would not want to share the stacktrace with your client. But generally log something twice is bad.

    10. More (handling) code, potentially more bugs, definitely (relatively) slower, and just a bloody mess to maintain especially with all that pollution caused by your usage of logging which has in general an economic value of 0$.

    Software development is not an easy task, mentoring, talking about things like that within your organisation is essential.

  9. An exceptionally bad start[ Go to top ]

    I actually said "fill". getStackTrace() clones a StackTraceElement[] array which itself is built up from a native structure created/marked in the "fillInStackTrace" call in the constructor of Throwable. This has gotten faster over releases but still relatively expensive from were I stand in performance cost.

  10. An exceptionally bad start[ Go to top ]

    Could you post you code here? When you say "recursive" are you actually talking about calling the same method recursively with some kind of int count down parameter?

  11. An exceptionally bad start[ Go to top ]

    For "new Exception().getStackTrace()" I see approx 0.26 ms cost per exception construction (not thrown). This seems to be nearly 10 times slower than you reported figures. Maybe its time for me to get a new machine. I create 300 individually named methods ;-(

  12. An exceptionally bad start[ Go to top ]

    For "new Exception().getStackTrace()" I see approx 0.26 ms cost per exception construction (not thrown). This seems to be nearly 10 times slower than you reported figures. Maybe its time for me to get a new machine. I create 300 individually named methods ;-(

    I was too lasy to create 300 methods. :-) Maybe getting it for the same method benefits from some kind of cache. (Or you really should change your box :-)

    Cheers,

    T

     

  13. An exceptionally bad start[ Go to top ]

    I was too quick with my previous post.

    I got the same value for 300 methods: 0.27ms, the 0.03ms is when you just throw it without getStacktrace().

     

  14. An exceptionally bad start[ Go to top ]

    Is your method with and without throwing exception contained any code except throw and return statements?

    Usually performance testing with empty methods does not give clear picture since they are optimized by VM. 

    Its better to add some type of time consuming code in it (like looping or even call to toString() ) before throwing exception or returning a value.

  15. An exceptionally bad start[ Go to top ]

    Is your method with and without throwing exception contained any code except throw and return statements?

    Usually performance testing with empty methods does not give clear picture since they are optimized by VM. 

    Its better to add some type of time consuming code in it (like looping or even call to toString() ) before throwing exception or returning a value.

    Hi,

    It is a recoursion + count down. I tought of doing something else in the method, just to be sure, but after seeing that it was 2 magnitudes slower I did not though that could be some kind of voodoo. It seems that ca. 0.13ms is needed to throw an exception :-) Which is a penalty I can live with for an exceptional case :-) (not for a loop of course)

    The test class can be found under:

    ?http://dl.dropbox.com/u/18770076/ExeptionalTest.java

    My setup was:

    Intel(R) Core(TM)2 Duo CPU     E8500  @ 3.16GHz + Linux 2.6.24-28-386 + Java(TM) SE Runtime Environment (build 1.6.0_22-b04) Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)

    The results were more or less the same on my notebook using WinXP. Running it twice  (in the same VM) did alter a bit the results, but all of the methods benefited from JIT ca. in the same percentage.

    I think a clean readable code worth this penalty. (If it would be 1/2 sec, that would be outrageous though)

    Cheers,

    T

  16. I'm loking at both argumets given and numbers provided, and that somehow doesn't fit together to make the problem important from the performance perspective.

    E.g.

    - getStackTrace() for 300 stack frames takes 0.25 ms

    - Assumption: some method with database call normally returns in 50 ms (which IMO generally would be a rather optimistic assumption)

    - I'm trying to figure out the overhead of exceptional case in %

    - Assumption: the method throws an exception _after_ it spent its regular 50 ms, so all overhead goes on top of regular timing

    - Assumption: somehow the application calls getStackTrace() 4 times (directly or indirectly).

    - Math: 4 x 0.25 = 1ms spent on getting exception stack traces. It is 2% of 50 ms.

    - So with this exception handling, the application may slow down by 2% under exceptional conditions.

    Normally I wouldn't call this impact terribly expensive, or important at all. 

    But perhaps there is a problem with assumptions? If so, what assumptions would one need to see significant slowdown caused by improper exception handling, in %?

     

  17. 50 ms for a single database call is a ridiculously slow operation. The banks we work with have queries performed in single digits. And lets not forget that not every single enterprise Java application out there uses a database in its critical execution paths though I am sure some others would love this to be the case. Just look at the usage of data/compute grids to reduce this db type latency.

  18. The article I referenced shows JBoss AS creating more than 21,000 exceptions just in starting up.

    Everything in moderation is the rule.

    Measurements up to this point have not factored in the impact beyond the test execution (i.e. increased likelihood of gc which can be a stop the world event multiplying the impact by the number of concurrent threads). For some of us every nanosecond matters never mind microsecond and milliseconds. Its all relative to the environment, nature of work and performance constraints.

    That said I think you would be surprised by how much exception generation does happen in the typical web/spring/javaee app created by joe the plumbers sourced as programmers.

    And yes I think the overhead has been understated here due to usage of micro-benchmarks. I hope to address this very soon if some other things clear up.

    If you created a common cost/operation table today stack trace collection via exception creating, printing, logging and whatever else people do with such crude diagnostic mechanisms it would be up at the top.

    One poster was right that it can pale in comparison to the other issues with most poorly developed/tested/tuned web apps and their frameworks (though some do generate such things routinely).

    There is no need to incur this cost which is relatively high to local execution costs if need be.

    A little jab but if you are using dynaTrace for APM then exception costs are the least of your worries ;-)

  19. steve hyland[ Go to top ]

    this is an absurd post and shows the qulity of postings on this site. obviously , if you log a few megabytes of stack traces and data your exception will take a few milliseconds.. but who does this more than a few times in an application? it is the most rediculous and amateurish posting i have seen here yet.. what will we have next.. the dangers of empty loops.. did you know if you loop  within a loop within a loop doing nothing your application may slow down.. be sure not to write empty loops with more than a few billion no-ops..

  20. Absurd, but true[ Go to top ]

    this is an absurd post...

    Maybe a bit simplistic, but hardly absurd. Every developer profess to strive for proper error logging and claim to excersise exception-handling discipline... yet the software-world is RIDDLED with examples of the most horrible examples of bad exception handling. Case in point, almost every application server I have ever worked with. The common pattern seems to be "log with stack trace in every layer, re-throw with nested exception and log again". If you want a really nice example, take a look at WebSphere. In exception thrown will render an avalanche of logging with stack-traces hundreds of calls deep and 5 levels of nesting. Is that proper?

    Even the SDK has offenders. Someone mentioned the classloader, which is a good example. Why should I have to catch a ClassNotFound exception, when a null return-value could easily inidicate the same thing?

    If anything is absurd, it's how we all consistently say one thing but do the exact opposite when it comes to proper exception-handling and logging.

  21. I disagree[ Go to top ]

    Even the SDK has offenders. Someone mentioned the classloader, which is a good example. Why should I have to catch a ClassNotFound exception, when a null return-value could easily inidicate the same thing?

    The purpose of Checked exceptions is to force the caller handle erroneous situations. If Class.forName returns a null then your client code would be doing some operation on a null which would cause a NullPointerException which would be spurious. The purpose of the forName throwing a checked exception is to force you write an alternative code if the class being loaded is not available which is very much the right way to proceed. Returning a null does not force you.Returning null might not be suitable for all situations

  22. Will we ever learn[ Go to top ]

    Its funny to hear this discussion from time to time. It is popping up in different shapes now and then. Some developers like to discuss perfomance and long ago this was relevant. CPU-cycles used to be expensive but that was long ago. CPU is cheap these days, anything within the cpu or even on the bus is cheap enough to be irrelevant in this discussion. As someone said earlier in this thread, syncronous waits on databases or general Io's are the things that sould bother us as developers. A much more interesting question these days (as have been for a long time) is the maintenance of software. If you developed software for some time you have realised that simplifying the code, increase the readability, is by far the most important aspect of software development. With this in mind, getting the "out of bands" code out of the main path is a good thing. I thing the Spring guys got it right, throw RuntimeException for things you cant handle and catch them while testing. The cost of doing so is irrelevant.. It may take minutes to parse the call stack, it doesn't matter.. Readability does!

  23. So, what did we learn "Stop Handling Exceptions" OR "Handling Exceptions, but avoid using too many stack trace calls"? As per my practical experience, it is later. 

  24. You learned 

    1. Don't call getStacktrace for logging purposes or worse still for sampling purposes unless you are writing desktop applications.

    http://williamlouth.wordpress.com/2009/10/21/java-call-sampling-overhead-in-the-wild/

    2. You hopefully learnt not to throw exceptions liberally in libraries (@see JNDI)

    3. You hopefully learnt not to log and if you must not to repeat yourself up the stack

    http://williamlouth.wordpress.com/2010/11/24/everything-you-ever-needed-to-know-about-logging/

    4. The Alois can't write code or measure it properly ;-)

    5. To stay away from such discussions...

  25. That's definitely an issue, if not done properly. I was just measuring our web application and was wondering why the cpus where spinning at 80-90% (testing just with 15 threads with lot of waiting for queries). I found out that for a single page there were thrown about 3500! MissingResourceException just because everthing is looked up in (multple) ResourceBundles by default with code like this (web framework code, not application code):

     try {

    bundle.getString(key);

    } catch(MissingResourceException e){// do nothing, no stacktrace}

    Note that I am not against handling exceptions, but think about what you are doing.

    Cheers,

    Philip

     

     

     

  26. Handling exception is within the tenets of application programming. You can't just run away from it. I guess the important concern is how to "manage" the exception in such way that your performance is not impacted so much.

    Not handling the exception will help on one side (good performance) but has negative impact on the other side (not fulling business process). Exception management is good as it gives you information from the different aspects of solution (from network to business logic to application bugs).

     

  27. Ok, so dumping a stack trace may be slow but if your app is throwing a sufficient number of exceptions to make this anything but totally insignificant then you've either written your app in a very bad way (to rely on exceptions being thrown via the expected execution path) or you really do have some valid exceptions occuring that you should investigate and rectify.

    Here's the hint: the word is "EXCEPTION". It means the 'exception' to the rule or the 'unexpected' ie., not the norm. If exceptions have 'become the norm' to the point where performance is suffering because so many of them are being raised then seriously take a long hard look at the design and structure of your code.

  28. It's in the compiler theory, if anybody would bother to remember / read: Exception handling mechanism is slow compared with return values. It is the compromise between readability and machine. It is normally aggravated by reading activation records (getStackTrace()).

    Pushing activation records exception handlers on the stack and then, when the exception happens, verifying each activation record against the exception costs CPU, as it is normal.

    Hopefully exceptions are exceptional cases, and it should remain exceptional. If you reach the point where you ask why it takes so much time when the bad thing shows its face, there is really something wrong with your program.

     

  29. How to measure properly[ Go to top ]

    Alois here is an article that will help you to understand how better to measure overhead.

    How To Meter Anything: An Exceptional Start