Skip to content

Commit 14136fa

Browse files
committed
Trying to resolve [Issue-5], unintended object retention causing OOME
1 parent f9cd5f0 commit 14136fa

File tree

4 files changed

+53
-19
lines changed

4 files changed

+53
-19
lines changed

pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
<parent>
44
<groupId>org.sonatype.oss</groupId>
55
<artifactId>oss-parent</artifactId>
6-
<version>5</version>
6+
<version>7</version>
77
</parent>
88
<groupId>com.fasterxml.util</groupId>
99
<artifactId>java-merge-sort</artifactId>
1010
<name>java-merge-sort</name>
11-
<version>0.6.1-SNAPSHOT</version>
11+
<version>0.7.0-SNAPSHOT</version>
1212
<packaging>bundle</packaging>
1313
<description>Basic disk-backed N-way merge sort
1414
</description>
@@ -119,11 +119,11 @@
119119
<plugin>
120120
<groupId>org.apache.felix</groupId>
121121
<artifactId>maven-bundle-plugin</artifactId>
122-
<version>2.3.4</version>
122+
<version>2.3.7</version>
123123
<extensions>true</extensions>
124124
<configuration>
125125
<instructions>
126-
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
126+
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
127127
<Bundle-Vendor>com.fasterxml</Bundle-Vendor>
128128
<Import-Package>
129129
</Import-Package>

release-notes/VERSION

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Version: 0.7.0
2+
3+
Release date:
4+
29-May-2012
5+
6+
Description:
7+
Another pre-1.0 release
8+
9+
Fixes:
10+
11+
* [Issue-5]: Unnecessary object retention, leading to too high memory usage
12+
(reported by Paul Smith)
13+
14+
------------------------------------------------------------------------
15+
=== History: ===
16+
------------------------------------------------------------------------
17+
18+
2.0.2 (16-May-2012)
19+

src/main/java/com/fasterxml/sort/Sorter.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,12 @@ public void sort(InputStream source, OutputStream destination)
195195
*
196196
* @return true if sorting completed succesfully; false if it was cancelled
197197
*/
198-
public boolean sort(DataReader<T> inputReader, DataWriter<T> resultWriter)
198+
public boolean sort(DataReader<T> inputReader, DataWriter<T> resultWriter)
199199
throws IOException
200200
{
201201
// First, pre-sort:
202202
_phase = SortingState.Phase.PRE_SORTING;
203203

204-
/* Minor optimization: in case all entries might fit in
205-
* in-memory sort buffer, avoid writing intermediate file
206-
* and just write results directly.
207-
*/
208204
SegmentedBuffer buffer = new SegmentedBuffer();
209205
boolean inputClosed = false;
210206
boolean resultClosed = false;
@@ -220,6 +216,10 @@ public boolean sort(DataReader<T> inputReader, DataWriter<T> resultWriter)
220216
}
221217
Arrays.sort(items, _rawComparator());
222218
T next = inputReader.readNext();
219+
/* Minor optimization: in case all entries might fit in
220+
* in-memory sort buffer, avoid writing intermediate file
221+
* and just write results directly.
222+
*/
223223
if (next == null) {
224224
inputClosed = true;
225225
inputReader.close();
@@ -318,6 +318,8 @@ protected List<File> presort(DataReader<T> inputReader,
318318
{
319319
ArrayList<File> presorted = new ArrayList<File>();
320320
presorted.add(_writePresorted(firstSortedBatch));
321+
// important: clear out the ref to let possibly sizable array to be GCed
322+
firstSortedBatch = null;
321323
do {
322324
Object[] items = _readMax(inputReader, buffer, _config.getMaxMemoryUsage(), nextValue);
323325
Arrays.sort(items, _rawComparator());
@@ -333,8 +335,10 @@ protected File _writePresorted(Object[] items) throws IOException
333335
@SuppressWarnings("unchecked")
334336
DataWriter<Object> writer = (DataWriter<Object>) _writerFactory.constructWriter(new FileOutputStream(tmp));
335337
++_presortFileCount;
336-
for (Object item : items) {
337-
writer.writeEntry(item);
338+
for (int i = 0, end = items.length; i < end; ++i) {
339+
writer.writeEntry(items[i]);
340+
// to further reduce transient mem usage, clear out the ref
341+
items[i] = null;
338342
}
339343
writer.close();
340344
return tmp;

src/main/java/com/fasterxml/sort/util/SegmentedBuffer.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.fasterxml.sort.util;
22

3+
import java.util.Arrays;
4+
35
/**
46
* Helper class used instead of a standard JDK list or buffer,
57
* to avoid constant re-allocations.
@@ -59,7 +61,9 @@ public SegmentedBuffer() { }
5961
*/
6062
public Object[] resetAndStart()
6163
{
62-
_reset();
64+
if (_bufferedEntryCount > 0) {
65+
_reset();
66+
}
6367
if (_freeBuffer == null) {
6468
return new Object[INITIAL_CHUNK_SIZE];
6569
}
@@ -115,6 +119,8 @@ public Object[] completeAndClearBuffer(Object[] lastChunk, int lastChunkEntries)
115119
int totalSize = lastChunkEntries + _bufferedEntryCount;
116120
Object[] result = new Object[totalSize];
117121
_copyTo(result, totalSize, lastChunk, lastChunkEntries);
122+
// [Issue-5]: should reduce mem usage here
123+
_reset();
118124
return result;
119125
}
120126

@@ -144,12 +150,17 @@ public int initialCapacity()
144150
private void _reset()
145151
{
146152
// can we reuse the last (and thereby biggest) array for next time?
147-
if (_bufferTail != null) {
148-
_freeBuffer = _bufferTail.getData();
153+
if (_bufferedEntryCount > 0) {
154+
if (_bufferTail != null) {
155+
Object[] obs = _bufferTail.getData();
156+
// also, let's clear it of contents as well, just in case
157+
Arrays.fill(obs, null);
158+
_freeBuffer = obs;
159+
}
160+
// either way, must discard current contents
161+
_bufferHead = _bufferTail = null;
162+
_bufferedEntryCount = 0;
149163
}
150-
// either way, must discard current contents
151-
_bufferHead = _bufferTail = null;
152-
_bufferedEntryCount = 0;
153164
}
154165

155166
private final void _copyTo(Object resultArray, int totalSize,
@@ -186,9 +197,9 @@ private final static class Node
186197
/**
187198
* Data stored in this node. Array is considered to be full.
188199
*/
189-
final Object[] _data;
200+
private final Object[] _data;
190201

191-
Node _next;
202+
private Node _next;
192203

193204
public Node(Object[] data) {
194205
_data = data;

0 commit comments

Comments
 (0)