ws-soap-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bill-s...@carpenter.ORG (WJCarpenter)
Subject RE: eliminating one or two in memory copies of the response payload
Date Tue, 02 Mar 2004 02:25:34 GMT
wjc> I'm developing an obsession with getting rid of unnecessary
wjc> copies during response processing.

I got a chance to work on this over the weekend, and things went well.
(I have it working perfectly for the case that I care about, but I
haven't yet proved to myself that I didn't goof up cases that I don't
run.  How's the coverage in the Apache SOAP regression test suite?)
Anyhow, I thought I would report some initial numerical results
because it contains a bit of a puzzle.

I ran a series of tests where the response payload varied in 10 steps
from just under 200 kbytes to just under 2 mbytes (actually, just dumb
luck that it was nice round numbers).  My response data is fairly
typical SOAP encoding: "lots of little nested elements".  I compared
the results of running with my modification ("stream") versus the
status quo ("preread").  To avoid having made a blunder in the
"preread" case, I ran that test pass using an unmodified soap.jar
built from a current CVS snapshot.

To recap, for a simple single-part RPC call, "preread" reads the
entire response payload into a byte[] and then converts it to a String
before parsing.  The "stream" modification avoids the byte[] and
String versions and feeds the original InputStream into the XML

As you might guess, processing times are slightly better with "stream"
since the time to copy into memory is eliminated.  In my tests, the
ratio was pretty linear and averaged out to just under 4%.

The difference in collectible memory footprint is a bigger mystery,
though.  For this, I forced GC and then recorded free memory before
and after my individual stepped test calls.  I ran with a large
min/max heap to avoid spurious GCs inside a test call.  Given Java's
16-bit characters and the two in-memory copies described above, one
would've naively expected the difference between "stream" and
"preread" runs to be about 3 times the payload size.  That's a slight
miscalculation because the copy into a byte[] uses a doubling
algorithm and then resizes at the end of it all, so that's about 2x in
scratch buffers, for a total of 5x collectible memory. In fact, the
measured difference is pretty consistent across all the steps and is
approximately 9 times the payload size.

For example, at the 1 mbyte payload step, the difference is about 9
mbytes, whereas the expected difference would be only about 5 mbytes.

I don't know what to conclude about this except that maybe the XML
parser is a lot more efficient in memory at parsing from an
InputSource backed by an InputStream than it is parsing from one
backed by a String.  (It's possible that I've missed some in-memory
copying in soap.jar before getting to the XML parsing, but that seems
unlikely given the number of times I've step-debugged through this
recently.)  Anyhow, the good news is that the results for "stream" are
even better than expected.
bill@carpenter.ORG (WJCarpenter)    PGP 0x91865119
38 95 1B 69 C9 C6 3D 25    73 46 32 04 69 D6 ED F3

View raw message