setLength(0) or delete( 0, length())

Q

qazmlp

The heap profiler(HAT available with Solaris) always reports that,
there are memory leaks in the code wherever my code has the following
statement.
strBuf.delete(0, strBuf.length());

What could be the reason? Do I have to use
strBuf.setLength(0) ?

Kindly clarify it!
 
A

Alan Moore

The heap profiler(HAT available with Solaris) always reports that,
there are memory leaks in the code wherever my code has the following
statement.
strBuf.delete(0, strBuf.length());

What could be the reason? Do I have to use
strBuf.setLength(0) ?

Kindly clarify it!

No, you need to create a new StringBuffer:

strBuf = new StringBuffer();

StringBuffers are not meant to be reused; this memory leak is the
result of trying to do so (in some JDK versions, that is).
 
B

Bryan E. Boone

Really?
I've never known about that one. Can you tell me where I can find the
discussions on this?

-Bryan
 
X

xarax

Alan Moore said:
No, you need to create a new StringBuffer:

strBuf = new StringBuffer();

StringBuffers are not meant to be reused; this memory leak is the
result of trying to do so (in some JDK versions, that is).

That is total baloney. Any JDK that causes a memory leak
with StringBuffer is broken.

The OP must post more information about what
is happening with his reference to a StringBuffer. If
it is retained somewhere (like in a list), then it may
not be eligible for garbage collection.

setLength() and delete(), under these circumstances,
should allocate any new memory. They should be adjusting
the start,end bounds. If delete() is leaking memory, then
the its implementation is broken. Period.

btw: setLength(0) will likely be faster than deleting
the chars in the internal char array, because StringBuffer
must examine the start,end values and calculate what's
left over, if any. setLength(0) is easy, it just sets
the end bound to the value specified.
 
?

=?ISO-8859-1?Q?Daniel_Sj=F6blom?=

qazmlp said:
The heap profiler(HAT available with Solaris) always reports that,
there are memory leaks in the code wherever my code has the following
statement.
strBuf.delete(0, strBuf.length());

If you read the source of StringBuffer you will see that the pointer to
the char array that StringBuffer uses internally is never released by
delete(). This is not a bug per se, but it would be better if Sun added
a special clause to deal with delete(0, len), which should obviously
always release the pointer (like setLength(0))
What could be the reason? Do I have to use
strBuf.setLength(0) ?

By reading the source again, you will see that setLength(0) will make
the internal array pointer refer to a new char[16]. Btw, reusing
StringBuffers is usually not a good idea, as you may have noticed.
 
B

Bryan E. Boone

That's what I figured, but I wanted to see if he had any info on it.
I've been using Java since JDK 1.0.2 Alpha and have never heard
of such memory leaks and StringBuffer.

-Bryan
 
D

Dale King

xarax said:
That is total baloney. Any JDK that causes a memory leak
with StringBuffer is broken.

Well it isn't total baloney. There are some things you can do that can cause
you to suck up a great deal of memory. Unfortunately, StringBuffer in the
Kaffe implementation and in JDK1.4.1 were broken (see below).

Alan is right that it is best to not use a StringBuffer anymore after you
call toString on them. You can do it, but there can be problems with excess
memory being used.

The issue is that they are trying to optimize string concatenation
operations. When you call toString on a StringBuffer, it doesn't create a
new character array for use by the String object, it simply uses the one
that was created by the StringBuffer. The copy isn't made until the next
time you modify the StringBuffer. Usually, once you create the String you
are done with the StringBuffer, so it makes sense to optimize this case. But
it leads to some gotchas.

When you modify a StringBuffer, it doesn't usually shrink the size of the
char array. So let's say we do this:

Vector v = new Vector();
StringBuffer sb = new StringBuffer( 100000 );
for( int i = 0; i < 5000; i++ )
{
sb.append( "a" );
v.add( sb.toString() );
sb.delete(0, sb.length());
}

This creates a vector containing 5000 single character strings, so this
should have no problem, right? We made the initial StringBuffer a bit larger
than we needed, but what does that matter?

On my machine that dies, running out of memory. We end up trying to create
5000 strings that have a 100000 character array of which we only use one
character. This is the kind of thing that the heap analysis tool is pointing
out.

If you are going to reuse the StringBuffer you need to setLength( 0 ). They
have a special optimization in there for this case. It has this comment:

// If newLength is zero, assume the StringBuffer is being
// stripped for reuse; Make new buffer of default size

This will shrink the StringBuffer array back down to its default size of 16.
Using that in the above code will create 1 string of 100000 and 4999 of 16
chars.

setLength(0) is the only operation that will actually shrink the array size
of the StringBuffer's character array and the size of the char array will
also be the size of the char array in a toString operation. Calling
setLength( 0 ) seems the only safe way to reuse a StringBuffer.

But this relies on that optimization being present in setLength( 0 ). Is
this a valid assumption? Apparently not. Here is a message about Kaffe,
which did not have this setLength optimization:
http://www.kaffe.org/pipermail/kaffe/2000-March/037964.html

But apparently Sun fell victim to this too. Apparently in 1.4.1 they
eliminated this setLength optimization and had to put it back in for 1.4.2.
That means that it can't be relied on, so you cannot assume the optimization
is there. The bug report also says that this may change yet again in 1.5.

See:
http://www.javaspecialists.co.za/archive/Issue068.html at the bottom
http://developer.java.sun.com/developer/bugParade/bugs/4724129.html

So the advice is never, ever, reuse a StringBuffer after you call toString
on it. It used to be safe if you called setLength(0) on it, but that cannot
be relied upon any more.

There are also some similar gotchas on substring calls on String, because it
shares memory as well.
 
J

Jon A. Cruz

Daniel said:
If you read the source of StringBuffer you will see...

Just remember that reading the sources will only give one how a specific
vendor solved a specific instance in a specific version of a specific VM.

Only use the language spec as authoritative. Treat everything in source
as mutable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top