Bug 55609 - c:forEach loop on integer range consumes unnecessary heap space in proportion to value for "end"
Summary: c:forEach loop on integer range consumes unnecessary heap space in proportion...
Status: RESOLVED WONTFIX
Alias: None
Product: Taglibs
Classification: Unclassified
Component: Standard Taglib (show other bugs)
Version: 1.1
Hardware: PC Linux
: P2 enhancement (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-09-28 22:04 UTC by Dan Armstrong
Modified: 2014-12-02 05:17 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dan Armstrong 2013-09-28 22:04:21 UTC
The implementation of iteration for a forEach tag over an integer range builds an array of all the Integer objects in the range, and then obtains an iterator via Arrays.asList(...).iterator().  The unnecessarily consumes a large amount of heap space when the value of "end" is large.

The method in this comment about performance is basically correct from a *time* perspective, but completely ignores *space* considerations.

The patch to iterate over an integer range without undue heap space follows.

For JSTL 1.1.1 in src/org/apache/taglibs/standard/tag/common/core/ForEachSupport.java:

// Begin added by AO Industries, Inc.
import java.util.NoSuchElementException;
// End added by AO Industries, Inc.



    private ForEachIterator beginEndForEachIterator() {
// Begin removed by AO Industries, Inc.
//        /*
//         * To plug into existing support, we need to keep 'begin', 'end',
//         * and 'step' as they are.  So we'll simply create an Integer[]
//         * from 0 to 'end', inclusive, and let the existing implementation
//         * handle the subsetting and stepping operations.  (Other than
//         * localizing the cost of creating this Integer[] to the start
//         * of the operation instead of spreading it out over the lifetime
//         * of the iteration, this implementation isn't worse than one that
//         * created new Integers() as needed from next().  Such an adapter
//         * to ForEachIterator could easily be written but, like I said,
//         * wouldn't provide much benefit.)
//         */
//        Integer[] ia = new Integer[end + 1];
//        for (int i = 0; i <= end; i++)
//            ia[i] = new Integer(i);
//        return new SimpleForEachIterator(Arrays.asList(ia).iterator());
// End removed by AO Industries, Inc.

// Begin added by AO Industries, Inc.
        // This implementation does not require heap space in proportion to the number of iterations.
        return new SimpleForEachIterator(
            new Iterator() {
                private final int end = ForEachSupport.this.end;
                private int next = 0;

                public boolean hasNext() {
                    return next <= end;
                }

                public Object next() {
                    if(next > end) throw new NoSuchElementException();
                    return Integer.valueOf(next++);
                }

                public void remove() {
                    throw new UnsupportedOperationException();
                }
            }
        );
// End added by AO Industries, Inc.
    }
Comment 1 Dan Armstrong 2013-09-28 22:14:38 UTC
One observation: Integer.valueOf was added in Java 1.5, so we'll need to stick with new Integer(next++) in the iterator.

- Thanks!!!
Comment 2 Dan Armstrong 2013-09-29 00:39:07 UTC
I've been looking into this further.  This enhancement has already been made in the 1.2 series of standard taglib.  I hope you will still add it to any future release of the 1.1 series.
Comment 3 Jeremy Boynes 2013-09-29 17:30:51 UTC
This has already been fixed in trunk and will be included in 1.2.0.RC2.
Leaving open for 1.1 but a new release of that branch is unlikely.
Comment 4 Jeremy Boynes 2014-12-02 05:17:53 UTC
Closing as 1.2.1 is released and no new release of 1.1 is likely.