Java Exceptions cause performance hit?

A

Andrea Desole

Steve said:
Gaak. I hope the JVM doesn't unroll the stack. It should be
using a simple (internal) hash map to 'jump' directly to the
correct catch clause. Yes, that adds a small bit to each
try block to adjust the hash map, but most of the work
for it can be done at translation time.

it's possible that I misunderstand; look at:

http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html#15494

After all, a map like that can be fairly hard to maintain (translation
time is probably not enough). Considering that the disadvantage is some
less performance when an exception is thrown, I think it makes sense
 
E

Eric Sosman

John said:
Eric, your "performance comparison" is slightly skewed. The
performance characteristics of the two approaches is highly dependent
on the number of iterations and the cost of checking for the
terminating condition. In your comparison the number of iterations
(100) times the cost of checking (i < array.length) is extremely small
compared to the cost of creating and throwing the exception. There are
many scenarios where the opposite is true.

It's usually considered a good idea to quote a few
snippets from the message you're replying to, in order to
give people some context. Keep in mind that propagation
of messages on Usenet is irregular and unsynchronized; it's
likely that some readers see your reply but do not see my
message, and have no idea what you're writing about.

To bring people up to date: A question asked about the
performance cost of using exceptions. I answered with a
simple illustration cribbed from "Effective Java" by Joshua
Bloch, showing two ways to loop through an array: one in
which the index is compared to the array length at each
iteration, and another where the loop simply runs until it
provokes ArrayIndexOutOfBoundsException, which is caught.
I also reported that on my machine the latter was some 15.5
times slower than the former on a 100-element array, and
invited the questioner to make his own measurements.

Now that we're all up-to-date ...

John, I'd be surprised to learn that there are "many
scenarios" where using exceptions for control flow is faster
than using more direct methods like `if'. It might be possible
to concoct such a scenario, but I think it would be difficult.
Consider: if the exception reports the same circumstance that
the `if' or whatever would have tested, the code that decides
to throw the exception must itself make the same test[1]. If
the `if' made the same test, the code could discover the
condition without the overhead of creating and processing the
exception object.

Of course, there's always the possibility of poor design.
Bloch points to Iterator.hasNext() in this regard: the method
is unnecessary in the sense that Iterator.next() will throw
NoSuchElementException when it "runs off the end," so a `try'
block could accomplish all the decision-making that hasNext()
enables.[2] So why does hasNext() exist? Because it's gobs
more efficient and requires less typing, that's why. If you're
confronted with an API designed by someone who hasn't taken this
lesson to heart, an API that offers the "moral equivalent" of
next() without a matching hasNext(), you have little choice but
to use what you're given -- and curse the designer.

Now, observe that next() must somehow make a test that's
equivalent to hasNext(), so the standard idiom for iteration
winds up making the test twice. If that test were expensive
(which it isn't for Iterator, but let's imagine some other
API offering such a pair of methods), it's just possible that
the cost of processing an exception might be smaller than the
cost of making two tests. My informal measurement gives some
rough idea of how expensive a test would need to be before
using exceptions became a practical alternative -- and the
answer is "very expensive indeed," more than the cost of 1500
integer-comparing `if's. I made no claim that this measurement
was highly accurate or was universal, but I'd be comfortable
with saying that the cost of one exception lies somewhere
North of a thousand simple `if' tests.

Yes, it's possible to write an expensive `if', most simply
by calling a few expensive methods inside it. I suggest that
such tests are not typically associated with exceptions: you
simply don't see code that calls BigInteger.probablePrime()
and throws an exception based on the result. (Or if you do,
you're looking at code unlike anything I've seen ...) If you
find "many scenarios" of this sort in the code you work with,
you have my sincerest sympathy.


[1] Or an equivalent test. If the equivalent is cheaper
than the original, one wonders why the `if' would make the
costlier test in the first place.

[2] Or almost. Bloch points out that it's difficult to
distinguish the "expected" exception when next() runs off
the end from an "unexpected" exception thrown because of a
bug somewhere in code executed elsewhere with the loop. A
simple try/catch around the whole loop lumps both together,
whereas hasNext() can easily tell the two conditions apart.
 
S

Steve Wampler

John Currier wrote:
John, I'd be surprised to learn that there are "many
scenarios" where using exceptions for control flow is faster
than using more direct methods like `if'. It might be possible
to concoct such a scenario, but I think it would be difficult.

Simply bumping your test from an 100 element array to a 50000
element array gives one:
=====================================================
->java -version
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode)
->cat Foo.java
import java.util.Date;

public class Foo {
public static void main(String args[]) {
int array[] = new int[50000];

long t1 = new Date().getTime();
for (int i = 0; i < array.length; ++i) {
array = i;
}
long t2 = new Date().getTime();

long t3 = new Date().getTime();
try {
for (int i = 0; ; ++i) {
array = i;
}
}
catch (ArrayIndexOutOfBoundsException ex) {}
long t4 = new Date().getTime();

System.out.println("T1 : "+(t2-t1)+"ms");
System.out.println("T2 : "+(t4-t3)+"ms");
}
}
->javac Foo.java
->java Foo
T1 : 5ms
T2 : 1ms
=====================================================
Granted, I think it's an odd way to program, but it certainly
wasn't hard to construct...
 
E

Eric Sosman

Steve said:
John Currier wrote:

John, I'd be surprised to learn that there are "many
scenarios" where using exceptions for control flow is faster
than using more direct methods like `if'. It might be possible
to concoct such a scenario, but I think it would be difficult.


Simply bumping your test from an 100 element array to a 50000
element array gives one:
[micro-benchmark]
T1 : 5ms [for ordinary loop]
T2 : 1ms [infinite loop with try/catch]

Um, er, I wouldn't even time a C code construct this
way, never mind a piece of Java. The time taken for just
one execution of a small piece of code simply isn't to be
trusted, especially not if it's the very first execution.
GC doesn't run, the JIT compiler doesn't run -- it's like
predicting someone's Marathon time by checking his crawling
speed in infancy.

Even in my first quick-and-dirty trial, I ran each
loop a thousand times to "warm up" the JVM, then timed each
loop on one thousand, ten thousand, ... repetitions until
the ratio of times settled down.
Granted, I think it's an odd way to program, but it certainly
wasn't hard to construct...

All right, you got me: I didn't think about the situation
enough. With a 50000-element array (and with warm-ups and
repetitions as described above), using an exception is about
7% faster than making comparisons. Specifically, I got 22855
vs. 21303 milliseconds for ten thousand repetitions of the two
loops (that's one billion array-element stores in all). So
now we've got two rough measurements of exception-processing
overhead: one exception costs as much as somewhere between
1500 and 47000 integer comparisons. (The wide range isn't to
be wondered at: we're just rediscovering the fact that the
derivative of 1/x is large when x is small. Of the two
measurements, I'd place a bit more faith in the latter.)
 
R

Raymond DeCampo

Steve said:
John Currier wrote:

John, I'd be surprised to learn that there are "many
scenarios" where using exceptions for control flow is faster
than using more direct methods like `if'. It might be possible
to concoct such a scenario, but I think it would be difficult.


Simply bumping your test from an 100 element array to a 50000
element array gives one:
=====================================================
->java -version
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode)
->cat Foo.java
import java.util.Date;

public class Foo {
public static void main(String args[]) {
int array[] = new int[50000];

long t1 = new Date().getTime();
for (int i = 0; i < array.length; ++i) {
array = i;
}
long t2 = new Date().getTime();

long t3 = new Date().getTime();
try {
for (int i = 0; ; ++i) {
array = i;
}
}
catch (ArrayIndexOutOfBoundsException ex) {}
long t4 = new Date().getTime();

System.out.println("T1 : "+(t2-t1)+"ms");
System.out.println("T2 : "+(t4-t3)+"ms");
}
}
->javac Foo.java
->java Foo
T1 : 5ms
T2 : 1ms
=====================================================
Granted, I think it's an odd way to program, but it certainly
wasn't hard to construct...


I think you will both have to work harder to prove anything. I got
similar results when I ran the code above. However, if I reversed the
order of the experiments, I got the opposite results:

=======================================================
$ java -version
java version "1.5.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_03-b07)
Java HotSpot(TM) Client VM (build 1.5.0_03-b07, mixed mode, sharing)
$ cat Foo.java
import java.util.Date;

public class Foo {
public static void main(String args[]) {
int array[] = new int[50000];

long t3 = new Date().getTime();
try {
for (int i = 0; ; ++i) {
array = i;
}
}
catch (ArrayIndexOutOfBoundsException ex) {}
long t4 = new Date().getTime();

long t1 = new Date().getTime();
for (int i = 0; i < array.length; ++i) {
array = i;
}
long t2 = new Date().getTime();

System.out.println("T1 : "+(t2-t1)+"ms");
System.out.println("T2 : "+(t4-t3)+"ms");
}
}
$ java -cp . Foo
T1 : 1ms
T2 : 14ms
=========================================================

Ray
 
S

Steve Wampler

..
With a 50000-element array (and with warm-ups and
repetitions as described above), using an exception is about
7% faster than making comparisons. Specifically, I got 22855
vs. 21303 milliseconds for ten thousand repetitions of the two
loops (that's one billion array-element stores in all). So
now we've got two rough measurements of exception-processing
overhead: one exception costs as much as somewhere between
1500 and 47000 integer comparisons. (The wide range isn't to
be wondered at: we're just rediscovering the fact that the
derivative of 1/x is large when x is small. Of the two
measurements, I'd place a bit more faith in the latter.)

So would I, in fact, I suspect the 47000 is pretty close to
being spot on. Increasing the array size beyond 50000 is
probably not going to show much change. Of course, that's
also a minimal exception cost. I'll bet the cost goes up
if the test is run in a more deeply nested call stack...
 
S

Steve Wampler

I think you will both have to work harder to prove anything. I got
similar results when I ran the code above. However, if I reversed the
order of the experiments, I got the opposite results:

Yes, my 'micro-benchmark', as Eric also points out, doesn't show
much. Eric's latest measures are much better.
 
J

John Currier

Partial quote...sorry, I thought that threading newsreaders were the
norm:
Now, observe that next() must somehow make a test that's
equivalent to hasNext(), so the standard idiom for iteration
winds up making the test twice. If that test were expensive
(which it isn't for Iterator, but let's imagine some other
API offering such a pair of methods), it's just possible that
the cost of processing an exception might be smaller than the
cost of making two tests.

I'm not sure how you can quantify the performance characteristics of
Iterator when it's an interface.

Comparing the cost of creating/throwing an exception to the cost of
making two tests is not relevant without knowing the number of
iterations. That cost of the exception is fixed plus the cost of one
test times the number of iterations. The alternative approach is the
cost of two tests times the number of iterations. Which approach has
more desireable scalability characteristics? Yes, the number of
iterations might have to be relatively high to see a benefit, but that
depends on the performance characteristics of all the pieces involved.

Note that I don't use the exception approach, but I wouldn't blindly
dismiss its appropriateness for a particular scenario.

John
 
M

Matt Atterbury

(e-mail address removed) writes:

I'm surprised no-one else has commented on/noticed this ...
Hi. I wanted to use exceptions to handle error conditions in my code.
I think doing that is useful, as it helps to separate "go" paths from
error paths. However, a coding guideline has been presented that says
"Use conventional error-handling techniques rather than exception
handling for straightforward local error processing in which a program
is easily able to deal with its own errors."

By "conventional error-handling," I believe they mean returning an
error code, or just handling the error without going to a catch block.


When I said that I'd prefer throwing and catching exceptions--and that,
in fact, exceptions is the "conventional error-handling technique" in
Java, I was told that since we have a real-time system, we can't afford
the performance hit caused by using exceptions.

I'm confident that whatever your system is, it is _not_ real-time. Your
superiors might think it's "time-critical" or even "pseudo-real-time" but
that's as far it could go in Java as I'm pretty sure it is impossible to code
a real-time system in Java since, AFAIK, you do not have access to real-time
clocks and hardware interrupts. And, I would be absolutely amazed if you guys
even went to trouble of coding your Java program using a "true" real-time
design (but, hey, amaze away :).

m.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top