JDK-6730473 : (coll) java.util.SubList.subList() unnecessarily prevents gc of original SubList
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2008-07-28
  • Updated: 2016-01-27
  • Resolved: 2011-01-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7Resolved
Related Reports
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
This feature requests borders on being a bug report.

In JDK 1.6.0_06 (and probably later versions), the method java.util.SubList.subList, which is in AbstractList.java, reads:

public List<E> subList(int fromIndex, int toIndex) {
   return new SubList<E>(this, fromIndex, toIndex);
}

Because of the "this" reference passed to the child SubList constructor, the child SubList prevents the parent SubList from garbage collection. This could be avoided if the call were:

  return new SubList<E>(this.l, this.offset + fromIndex, this.offset + toIndex);

(i.e. the list wrapped by the SubList should first be unwrapped, and then the original list should be re-wrapped with adjusted fromIndex and toIndex, instead of wrapping another SubList around the existing wrapper).

With this modification, the program below would run without OutOfMemoryError. Additionally, this would improve performance for access to SubList elements, as the call stack wouldn't have to go through so many layers of wrapping.


JUSTIFICATION :
I have an application where a List of candidate items gradually gets restricted to a smaller and smaller sublist. If subList() was implemented the way I propose above, I could just keep track of one List object and my performance and memory usage would always be fine. In the current implementation, however, I also have to pass integers a, b - the range of my remaining list - to all operations that work on the list.

This defeats the purpose of subList(), which was provided specifically so that operations on List wouldn't have to accept optional range parameters.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1. The provided sample program completes without OutOfMemoryError.
2. Accessing elements of an AbstractList.subList().subList()...subList() should be just as fast as accessing elements of an AbstractList.subList(), especially when the list implements RandomAccess.
ACTUAL -
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.RandomAccessSubList.subList(AbstractList.java:762)
	at Tester.main(Tester.java:8)

---------- BEGIN SOURCE ----------
import java.util.List;
import java.util.Collections;

public class Tester {
    public static void main(String[] args) {
        List<String> list = Collections.emptyList();
        for (int i = 0; i < 1000000000; i++) {
            list = list.subList(0, 0);
        }
    }
}


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Write my own

static <E> List<E> subList(List<E> list)

method which doesn't exhibit this behaviour. This is clumsy and is the kind of work of which the java core libraries should free us.

Comments
EVALUATION The original SubList is needed in order to propagate changes back to the root list. A weak reference to the original sublist could be used but that adds unncessary complication.
06-01-2011

PUBLIC COMMENTS It would be desirable to allow the original sublist to be GCed if the only remaining reference is a sublist of the sublist. The naive implementation could be done by making any sub-sub-list a sub-list of the original list rather than of the sub-list. There is, unfortunately, one impedement. Modifications made to any sub-list are bubbled back through their parent. In order to allow sub-lists to be GCed it would be necessary for each sub-sub-list to maintain two references, a hard reference to the original list and a weak reference to it's sub-list parent. As long as the weak reference remains valid then it would propagate changes through that parent list otherwise it would use the hard reference to the parent's parent. This seems overly complicated and inefficient to achieve the desired goal. Unless there is a strong sentiment that implementing the weak reference to sub-list parent solution is desirable I am tempted to close this issue as WONTFIX
17-12-2010

EVALUATION The suggested implementation in the report looks correct.
19-11-2010