What are the effects of exceptions on performance in Java?

前端 未结 17 2568
情深已故
情深已故 2020-11-22 01:21

Question: Is exception handling in Java actually slow?

Conventional wisdom, as well as a lot of Google results, says that exceptional logic shouldn\'t be used for n

17条回答
  •  一个人的身影
    2020-11-22 01:27

    Exception performance in Java and C# leaves much to be desired.

    As programmers this forces us to live by the rule "exceptions should be caused infrequently", simply for practical performance reasons.

    However, as computer scientists, we should rebel against this problematic state. The person authoring a function often has no idea how often it will be called, or whether success or failure is more likely. Only the caller has this information. Trying to avoid exceptions leads to unclear API idoms where in some cases we have only clean-but-slow exception versions, and in other cases we have fast-but-clunky return-value errors, and in still other cases we end up with both. The library implementor may have to write and maintain two versions of APIs, and the caller has to decide which of two versions to use in each situation.

    This is kind of a mess. If exceptions had better performance, we could avoid these clunky idioms and use exceptions as they were meant to be used... as a structured error return facility.

    I'd really like to see exception mechanisms implemented using techniques closer to return-values, so we could have performance closer to return values.. since this is what we revert to in performance sensitive code.

    Here is a code-sample that compares exception performance to error-return-value performance.

    public class TestIt {

    int value;
    
    
    public int getValue() {
        return value;
    }
    
    public void reset() {
        value = 0;
    }
    
    public boolean baseline_null(boolean shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            return shouldfail;
        } else {
            return baseline_null(shouldfail,recurse_depth-1);
        }
    }
    
    public boolean retval_error(boolean shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            if (shouldfail) {
                return false;
            } else {
                return true;
            }
        } else {
            boolean nested_error = retval_error(shouldfail,recurse_depth-1);
            if (nested_error) {
                return true;
            } else {
                return false;
            }
        }
    }
    
    public void exception_error(boolean shouldfail, int recurse_depth) throws Exception {
        if (recurse_depth <= 0) {
            if (shouldfail) {
                throw new Exception();
            }
        } else {
            exception_error(shouldfail,recurse_depth-1);
        }
    
    }
    
    public static void main(String[] args) {
        int i;
        long l;
        TestIt t = new TestIt();
        int failures;
    
        int ITERATION_COUNT = 100000000;
    
    
        // (0) baseline null workload
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            
    
                failures = 0;
                long start_time = System.currentTimeMillis();
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    boolean shoulderror = (i % EXCEPTION_MOD) == 0;
                    t.baseline_null(shoulderror,recurse_depth);
                }
                long elapsed_time = System.currentTimeMillis() - start_time;
                System.out.format("baseline: recurse_depth %s, exception_freqeuncy %s (%s), time elapsed %s ms\n",
                        recurse_depth, exception_freq, failures,elapsed_time);
            }
        }
    
    
        // (1) retval_error
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            
    
                failures = 0;
                long start_time = System.currentTimeMillis();
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    boolean shoulderror = (i % EXCEPTION_MOD) == 0;
                    if (!t.retval_error(shoulderror,recurse_depth)) {
                        failures++;
                    }
                }
                long elapsed_time = System.currentTimeMillis() - start_time;
                System.out.format("retval_error: recurse_depth %s, exception_freqeuncy %s (%s), time elapsed %s ms\n",
                        recurse_depth, exception_freq, failures,elapsed_time);
            }
        }
    
        // (2) exception_error
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            
    
                failures = 0;
                long start_time = System.currentTimeMillis();
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    boolean shoulderror = (i % EXCEPTION_MOD) == 0;
                    try {
                        t.exception_error(shoulderror,recurse_depth);
                    } catch (Exception e) {
                        failures++;
                    }
                }
                long elapsed_time = System.currentTimeMillis() - start_time;
                System.out.format("exception_error: recurse_depth %s, exception_freqeuncy %s (%s), time elapsed %s ms\n",
                        recurse_depth, exception_freq, failures,elapsed_time);              
            }
        }
    }
    

    }

    And here are the results:

    baseline: recurse_depth 2, exception_freqeuncy 0.0 (0), time elapsed 683 ms
    baseline: recurse_depth 2, exception_freqeuncy 0.25 (0), time elapsed 790 ms
    baseline: recurse_depth 2, exception_freqeuncy 0.5 (0), time elapsed 768 ms
    baseline: recurse_depth 2, exception_freqeuncy 0.75 (0), time elapsed 749 ms
    baseline: recurse_depth 2, exception_freqeuncy 1.0 (0), time elapsed 731 ms
    baseline: recurse_depth 5, exception_freqeuncy 0.0 (0), time elapsed 923 ms
    baseline: recurse_depth 5, exception_freqeuncy 0.25 (0), time elapsed 971 ms
    baseline: recurse_depth 5, exception_freqeuncy 0.5 (0), time elapsed 982 ms
    baseline: recurse_depth 5, exception_freqeuncy 0.75 (0), time elapsed 947 ms
    baseline: recurse_depth 5, exception_freqeuncy 1.0 (0), time elapsed 937 ms
    baseline: recurse_depth 8, exception_freqeuncy 0.0 (0), time elapsed 1154 ms
    baseline: recurse_depth 8, exception_freqeuncy 0.25 (0), time elapsed 1149 ms
    baseline: recurse_depth 8, exception_freqeuncy 0.5 (0), time elapsed 1133 ms
    baseline: recurse_depth 8, exception_freqeuncy 0.75 (0), time elapsed 1117 ms
    baseline: recurse_depth 8, exception_freqeuncy 1.0 (0), time elapsed 1116 ms
    retval_error: recurse_depth 2, exception_freqeuncy 0.0 (0), time elapsed 742 ms
    retval_error: recurse_depth 2, exception_freqeuncy 0.25 (24999999), time elapsed 743 ms
    retval_error: recurse_depth 2, exception_freqeuncy 0.5 (49999999), time elapsed 734 ms
    retval_error: recurse_depth 2, exception_freqeuncy 0.75 (99999999), time elapsed 723 ms
    retval_error: recurse_depth 2, exception_freqeuncy 1.0 (99999999), time elapsed 728 ms
    retval_error: recurse_depth 5, exception_freqeuncy 0.0 (0), time elapsed 920 ms
    retval_error: recurse_depth 5, exception_freqeuncy 0.25 (24999999), time elapsed 1121   ms
    retval_error: recurse_depth 5, exception_freqeuncy 0.5 (49999999), time elapsed 1037 ms
    retval_error: recurse_depth 5, exception_freqeuncy 0.75 (99999999), time elapsed 1141   ms
    retval_error: recurse_depth 5, exception_freqeuncy 1.0 (99999999), time elapsed 1130 ms
    retval_error: recurse_depth 8, exception_freqeuncy 0.0 (0), time elapsed 1218 ms
    retval_error: recurse_depth 8, exception_freqeuncy 0.25 (24999999), time elapsed 1334  ms
    retval_error: recurse_depth 8, exception_freqeuncy 0.5 (49999999), time elapsed 1478 ms
    retval_error: recurse_depth 8, exception_freqeuncy 0.75 (99999999), time elapsed 1637 ms
    retval_error: recurse_depth 8, exception_freqeuncy 1.0 (99999999), time elapsed 1655 ms
    exception_error: recurse_depth 2, exception_freqeuncy 0.0 (0), time elapsed 726 ms
    exception_error: recurse_depth 2, exception_freqeuncy 0.25 (24999999), time elapsed 17487   ms
    exception_error: recurse_depth 2, exception_freqeuncy 0.5 (49999999), time elapsed 33763   ms
    exception_error: recurse_depth 2, exception_freqeuncy 0.75 (99999999), time elapsed 67367   ms
    exception_error: recurse_depth 2, exception_freqeuncy 1.0 (99999999), time elapsed 66990 ms
    exception_error: recurse_depth 5, exception_freqeuncy 0.0 (0), time elapsed 924 ms
    exception_error: recurse_depth 5, exception_freqeuncy 0.25 (24999999), time elapsed 23775  ms
    exception_error: recurse_depth 5, exception_freqeuncy 0.5 (49999999), time elapsed 46326 ms
    exception_error: recurse_depth 5, exception_freqeuncy 0.75 (99999999), time elapsed 91707 ms
    exception_error: recurse_depth 5, exception_freqeuncy 1.0 (99999999), time elapsed 91580 ms
    exception_error: recurse_depth 8, exception_freqeuncy 0.0 (0), time elapsed 1144 ms
    exception_error: recurse_depth 8, exception_freqeuncy 0.25 (24999999), time elapsed 30440 ms
    exception_error: recurse_depth 8, exception_freqeuncy 0.5 (49999999), time elapsed 59116   ms
    exception_error: recurse_depth 8, exception_freqeuncy 0.75 (99999999), time elapsed 116678 ms
    exception_error: recurse_depth 8, exception_freqeuncy 1.0 (99999999), time elapsed 116477 ms
    

    Checking and propagating return-values does add some cost vs the baseline-null call, and that cost is proportional to call-depth. At a call-chain depth of 8, the error-return-value checking version was about 27% slower than the basline version which did not check return values.

    Exception performance, in comparison, is not a function of call-depth, but of exception frequency. However, the degredation as exception frequency increases is much more dramatic. At only a 25% error frequency, the code ran 24-TIMES slower. At an error frequency of 100%, the exception version is almost 100-TIMES slower.

    This suggests to me that perhaps are making the wrong tradeoffs in our exception implementations. Exceptions could be faster, either by avoiding costly stalk-walks, or by outright turning them into compiler supported return-value checking. Until they do, we're stuck avoiding them when we want our code to run fast.

提交回复
热议问题