Travis Woodruff wrote:
I think it's possible to retain even more than two copies of the keyval buffer.
This can happen because the comparator's buffer is set only when a comparison
is performed, so if no data exists for a partition in a spill cycle, the
partition's comparator will retain the buffer from a previous spill.
The sorter is the one that holds the reference to the comparator and all
the sorters (for all the partitions) are re-assigned before every spill
cycle. So all the earlier references will be lost. Similarly for the
first collect or the collect immediately after the spill, all the
sorters are re-initialized (for all the partitions). Hence I don't think
there is any way the buffers could be referenced beyond single level.
See HADOOP-2782 for more details.
Take this scenario:
We have 3 partitions: A,B,C
a keyval buffer that can hold 3 keys
and an input data set that generates output keys in the following sequence:
AAABBBCCC
A
A
A
-- Spill occurs here. A's comparator has keyval buffer 1.
B's and C's are null.
B
B
B
Overflow occurs here causing sorters to be re-assigned. All the
references are lost.
-- Spill occurs here. B's comparator has keyval buffer 2. A's comparator has
keyval buffer 1.
A's and C's are null.
C
C
C
Overflow occurs here causing the sorters to be re-assigned. Again all
the references are lost.
-- Spill occurs here. C's comparator has keyval buffer 3. B's A's comparator
has keyval buffer 2. A's comparator has keyval buffer 1.
A's and B's are null here. The simple fix would be as follows :
Index: src/java/org/apache/hadoop/mapred/MapTask.java
===================================================================
--- src/java/org/apache/hadoop/mapred/MapTask.java (revision 618559)
+++ src/java/org/apache/hadoop/mapred/MapTask.java (working copy)
@@ -505,9 +505,7 @@
sortSpillException = ioe;
} finally { // make sure that the collector never waits indefinitely
pendingKeyvalBuffer = null;
- for (int i = 0; i < partitions; i++) {
- pendingSortImpl[i].close();
- }
+ pendingSortImpl = null;
pendingKeyvalBufferLock.notify();
}
}
This is fairly unlikely, but I think it happening to me occasionally because
I'm seeing OOMEs I can't explain any other way. My heap is more than large
enough to support two 100M buffers.
FYI, I added code to clear the comparator's buffer (see patch below), and a job
that was failing with 650M heaps now succeeds with 512M.
Travis
Index: src/java/org/apache/hadoop/io/WritableComparator.java
===================================================================
--- src/java/org/apache/hadoop/io/WritableComparator.java (revision 618649)
+++ src/java/org/apache/hadoop/io/WritableComparator.java (working copy)
@@ -78,6 +78,11 @@
}
}
+ /** Free up memory used by the internal DataInputBuffer. */
+ public void clearBuffer() {
+ buffer.reset(new byte[] {}, 0, 0);
+ }
+
/** Optimization hook. Override this to make SequenceFile.Sorter's scream.
*
* <p>The default implementation reads the data into two [EMAIL PROTECTED]
Index: src/java/org/apache/hadoop/mapred/BasicTypeSorterBase.java
===================================================================
--- src/java/org/apache/hadoop/mapred/BasicTypeSorterBase.java (revision
618649)
+++ src/java/org/apache/hadoop/mapred/BasicTypeSorterBase.java (working copy)
@@ -124,6 +124,7 @@
//release the large key-value buffer so that the GC, if necessary,
//can collect it away
keyValBuffer = null;
+ comparator.clearBuffer();
}
//A compare method that references the keyValBuffer through the indirect
//pointers
----- Original Message ----
From: Amar Kamat <[EMAIL PROTECTED]>
To: [email protected]
Sent: Tuesday, February 5, 2008 12:08:48 AM
Subject: Re: Possible memory "leak" in MapTask$MapOutputBuffer
Hi,
Yes,
you
are
correct.
The
reference
to
the
old
keyval
buffers
are
still
there
even
after
the
buffers
are
re-initialized
but
the
reference
is
there
just
between
the
consecutive
spills.
The
scenario
before
HADOOP-1965
was
that
the
memory
used
for
one
sort-spill
phase
is
io.sort.mb
causing
the
max
memory
usage
to
be
(2
*
io.sort.mb).
Post
HADOOP-1965,
the
total
memory
used
for
once
sort-spill
phase
is
io.sort.mb/2,
the
max
memory
usage
is
io.sort.mb
and
the
time
duration
between
two
consecutive
spills
is
also
reduced
since
they
happen
in
parallel.
Thanks
for
pointing
it
out.
I
have
opened
HADOOP-2782
addressing
the
same.
Amar
Travis
Woodruff
wrote:
Well,
this
is
what
I
get
for
not
doing
my
homework
first.
I
pulled
down
the
latest
code
from
trunk,
and
it
looks
like
the
updates
for
HADOOP-1965
have
changed
this
code
significantly.
From
what
I
can
tell,
these
changes
have
removed
the
issue;
however,
the
problem
still
exists
in
the
0.15
branch.
Travis
-----
Original
Message
----
From:
Travis
Woodruff
<[EMAIL PROTECTED]>
To:
[email protected]
Sent:
Monday,
February
4,
2008
6:41:31
PM
Subject:
Possible
memory
"leak"
in
MapTask$MapOutputBuffer
<snip for goofy formatting>
____________________________________________________________________________________
Never miss a thing. Make Yahoo your home page.
http://www.yahoo.com/r/hs