ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

The Performance of Java's Lists
Pages: 1, 2, 3

Additionally, the ArrayList generates only a few extra objects for garbage collection, i.e. the internal array object which holds the elements, and one extra internal array object each time the ArrayList capacity is exhausted and the ArrayList needs to be grown. The LinkedList generates one node object for every insertion, irrespective of any deletions that might take place. Consequently, LinkedLists can make considerably more work for the garbage collector. Taking these added factors into account, my inclination would be to use an ArrayList rather than a LinkedList for any small to medium sized collection.

Table 2: Building a large collection (10 000 elements).

 

1.2 JVM

1.3 JVM

HotSpot 2.0 JVM

Always inserting at the start of the ArrayList

7773%

7537%

7500%

Always inserting at the start of the LinkedList

100%

90.34%

65.6%

Always inserting at the mid-point of the ArrayList

3318%

3412%

3121%

Always inserting at the mid-point of the LinkedList

26264%

14315%

14209%

Always inserting at the end of the ArrayList

41.4%

41.2%

37.5%

Always inserting at the end of the LinkedList

66.4%

73.9%

61.7%

Moving into the range of larger sized collections, we can see from table 2 that we begin to get a severe performance penalty when we encounter large insertion overheads. The worst case for LinkedList is, as we predicted from the analysis of the implementation, inserting to the middle of the collection. We can also see that this has worse performance than the ArrayList worst case of insertion to the start of the collection. Insertion to the middle of the ArrayList has significantly better performance than those two worst cases.



Overall, ArrayList again gives better performance for most cases, including index insertion to random locations. If you always need to insert toward the beginning of the collection, LinkedList provides a better performance but you can achieve even better performance using a reversed ArrayList, i.e. either with a dedicated implementation or by flipping indexes using a [size-index] mapping.

Table 3: Building a very large collection (1 000 000 elements).

 

1.2 JVM

1.3 JVM

HotSpot 2.0 JVM

Always inserting at the start of the ArrayList

too long

too long

too long

Always inserting at the start of the LinkedList

100%

179.5%

144.1%

Always inserting at the mid-point of the ArrayList

too long

too long

too long

Always inserting at the mid-point of the LinkedList

too long

too long

too long

Always inserting at the end of the ArrayList

38.3%

47.7%

42.9%

Always inserting at the end of the LinkedList

65.1%

161.5%

139.9%

Table 3, showing the results for very large collections, indicates conclusions very similar to those of table 2. However table 3 serves to emphasize that very large collections need particularly close matches between data, collection types, and data manipulation algorithms. Otherwise you can end up with performance that is essentially unusable. For optimum performance you should build a dedicated collection class implementation specific to the problem. For very large collections, it is often necessary to do this just in order to obtain adequate performance.

Querying performance

Querying is most efficiently achieved by implementing the query inside the class (see the two articles about optimizing queries, listed in the resources). The time needed to iterate over all the elements is the limiting factor for queries on these lists. A query implemented in the ArrayList/Vector classes will iterate over the array elements. The following example counts the number of null elements:

int count = 0;
for (int i = 0; i < size; i++)
  if(elementData[i] == null)
    count++;

A query implemented in the LinkedList class will traverse all the nodes. The following example counts the number of null elements:

node = header.next;
count = 0;
for (int i = 0; i < repeat; i++, node = node.next)
  if (node.element == null)
    count++;

Table 4 shows the ArrayList providing significantly superior performance to that of the LinkedList, once again indicating that ArrayList is the recommended class to use. Table 5 shows the time taken to iterate over all the elements using a ListIterator object obtained from the List.listIterator(int) method. These iterators would be necessary if the query could not be implemented in the List class. Once again, ArrayList shows superior performance, though not as dramatically as with table 4. Note that the absolute times in table 5 are about ten times longer than the absolute times in table 4, i.e. ArrayList internal traversal is about ten times faster than ArrayList iteration using a ListIterator.

ble 4: Iterating through all the elements of the collection using internal access

 

1.2 JVM

1.3 JVM

HotSpot 2.0 JVM

ArrayList internal traversal

100%

106%

197%

LinkedList internal traversal

470%

493%

448%


Table 5: Iterating through all the elements of the collection using a ListIterator

 

1.2 JVM

1.3 JVM

HotSpot 2.0 JVM

ArrayList iteration using ListIterator

100%

118%

75.2%

LinkedList iteration using ListIterator

117%

186%

156%

Conclusions

Related Reading

Java Performance TuningJava Performance Tuning
By Jack Shirazi
Table of Contents
Index
Sample Chapter
Full Description
Read Online -- Safari

The measurements and the other factors we've considered clearly indicate that ArrayLists and Vectors usually provides better performance than LinkedLists and synchronized wrapped LinkedLists. Even in cases where you might have thought that the LinkedList would provide better performance, you may be able to coax superior performance from ArrayList by altering how elements are added, for example by reversing the collection order.

There are situations where LinkedLists will provide better performance; with, for example, very large collections where many elements need to be added to both the beginning and end of the collection. But in general, I recommend using ArrayList/Vector as the default and using LinkedList only where there is an identified performance problem in which a LinkedList improves the performance.

Further resources

Jack Shirazi is the author of Java Performance Tuning. He was an early adopter of Java, and for the last few years has consulted mainly for the financial sector, focusing on Java performance.


Return to ONJava.com.