RFR: 8371164: ArrayList.addAll() optimizations

jengebr duke at openjdk.org
Tue Nov 4 14:58:57 UTC 2025


On Mon, 3 Nov 2025 21:41:47 GMT, Archie Cobbs <acobbs at openjdk.org> wrote:

>> # JVM Collections Optimizations: Eliminating toArray() Performance Bottlenecks
>> 
>> ## Summary
>> 
>> This PR addresses performance bottlenecks in ArrayList.addAll() and Collections.SingletonSet.toArray() methods by implementing direct optimizations that bypass inefficient intermediate allocations and abstract implementations. The optimizations target high-frequency operations identified through profiling analysis, delivering 37% performance improvements for ArrayList operations and 17-43% performance improvements for SingletonSet operations under real-world conditions where multiple collection types are used.
>> 
>> ## Problem Context
>> 
>> ### ArrayList.addAll() Inefficiency
>> ArrayList.addAll() currently calls `c.toArray()` on the source collection to avoid iterator-based copying, but this creates unnecessary intermediate array allocation when the source is also an ArrayList. The method performs:
>> 
>> 1. Call `c.toArray()` - creates intermediate array
>> 2. Call `System.arraycopy()` to copy from intermediate array to destination
>> 3. Discard intermediate array
>> 
>> When both source and destination are ArrayList instances, this can be optimized to direct array copying.
>> 
>> ### Collections.SingletonSet toArray() Missing Implementation
>> Collections.SingletonSet inherits the default `AbstractCollection.toArray()` implementation, which:
>> 
>> 1. Creates an Object[] of the expected size
>> 2. Iterates through the collection (1 element)
>> 3. Ensures "expected" size is the actual size
>> 4. Returns the array
>> 
>> For a single-element collection, this overhead is disproportionate to the actual work needed. Additionally, this implementation is vulnerable to call site poisoning, showing 74-118% performance degradation under megamorphic conditions.
>> 
>> ## Optimized Methods
>> 
>> ### ArrayList
>> - **`addAll(Collection<? extends E> c)`**: Added fast path for ArrayList-to-ArrayList copying using direct `System.arraycopy()` from source's internal `elementData` array, eliminating intermediate `toArray()` allocation
>> 
>> ### Collections.SingletonSet
>> - **`toArray()`**: Direct implementation returning `new Object[] {element}`
>> - **`toArray(T[] a)`**: Direct implementation with proper array sizing and null termination per Collection contract
>> 
>> ## Performance Impact
>> 
>> | Class | Method | Size | Baseline | Optimized | Improvement |
>> |-------|--------|------|----------|-----------|-------------|
>> | ArrayList | addAll | 0 | 10.149 ns/op, 40 B/op | 3.929 ns/op, 24 B/op | **...
>
> src/java.base/share/classes/java/util/ArrayList.java line 758:
> 
>> 756:             int numNew = src.size;
>> 757:             if (numNew == 0)
>> 758:                 return false;
> 
> Previously `addAll()` with an empty list would increment `modCount`, whereas now it won't. Might want to move this test down after `modCount++` to avoid the unnecessary behavioral change.

Will definitely fix, thank you for the catch!

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/28116#discussion_r2490839459


More information about the core-libs-dev mailing list