Search code examples
javaperformancejvmvariadic-functionsjit

JVM smart enought to optimize vararg array?


Given we have a method like this and we want to be as fast and memory efficient as possible. Is it likely that JVM will be smart enought to optimize this into simple string builder appends and avoid creating Object[] for varargs and avoid autoboxing primitives into Object for that object array?

protected String stringId(Object... things) {
    final StringBuilder sb = new StringBuilder();

    for (Object thing : things) {
        if(sb.length() > 0) {
            sb.append('-');
        }
        sb.append(String.valueOf(thing));
    }

    return sb.toString();
}

Solution

  • The temporary array to hold the variable arguments is created at the call site and each call site will get optimized individually and may have the object allocation elided or not. It would require inlining of your method to the caller to allow the optimizer to prove that the array is purely temporary, i.e. does not escape.

    However, whether this happens or not, is irrelevant. In an unoptimized execution scenario, you have a base footprint of at least five object instances, the array for the varargs, a StringBuilder and its backing array and the result String and its backing array. Then, for each argument that is not already a String or specially handled value (like null or a boolean), the invocation String.valueOf(thing) may return a new String instance, with a new backing array, before getting appended to the StringBuilder.

    Also the StringBuilder’s backing array starts with a default capacity of 16 chars and will get replaced by a larger array each time the capacity is exhausted.

    As said, that’s all for the unoptimized execution scenario and the optimizer will find a lot of optimization opportunities among these operations which have a much bigger impact than that sole array instance created for the varargs parameter. This also applies for values that needs to be auto-boxed. This auto-boxing happens at the caller as well and is subject to optimizations dedicated specifically to auto-boxing. For certain values, it is even mandatory to evaluate to the same object each time they get boxed.

    Note that the often-overlooked real expenses are at different places. E.g., converting numerical values to their decimal representations is far more expensive than wrapping these values into a lightweight Integer, resp. Double object.