String.valueOf() Memory Leak inside of thread.

T

Thomas Hawtin

This is causing a memory leak. If I change the line to read "String
str = "String.valueOf("1"); there is no problem. Also, if I do
something like: String str = "Hello world!"; there is also no problem.

If I use String.valueOf(1); inside the loop but outside of the thread,
there is no problem. Can anyone see why garbage collection is not
occurring inside the thread?

Are you sure you aren't just causing vast numbers of threads to be
running at once? Does shoving in a thread.join() fix it for you?

Tom Hawtin
 
B

BLlewellyn

If anyone could shed some light, I'd appreciate it.

I have a simple class with a main method. Inside the main method is a
loop. Each iteration of that loop instantiates an anonymous thread
whose run method contains a single line:

String str = String.valueOf(1);

This is causing a memory leak. If I change the line to read "String
str = "String.valueOf("1"); there is no problem. Also, if I do
something like: String str = "Hello world!"; there is also no problem.

If I use String.valueOf(1); inside the loop but outside of the thread,
there is no problem. Can anyone see why garbage collection is not
occurring inside the thread?

Thanks.

--Bradley


public class Main {
public static void main(String[] args) {
Thread thread = null;
for ( int intLoop = 0; intLoop < 10000; intLoop++ ) {
String myString;
myString = String.valueOf(1);
thread = new Thread() {
public void run() {
String str = String.valueOf(1);
}
};
thread.start();
thread=null;
System.gc();
}
}
}
 
R

Robert Klemme

If anyone could shed some light, I'd appreciate it.

I have a simple class with a main method. Inside the main method is a
loop. Each iteration of that loop instantiates an anonymous thread
whose run method contains a single line:

String str = String.valueOf(1);

This is causing a memory leak. If I change the line to read "String
str = "String.valueOf("1"); there is no problem. Also, if I do
something like: String str = "Hello world!"; there is also no problem.

If I use String.valueOf(1); inside the loop but outside of the thread,
there is no problem. Can anyone see why garbage collection is not
occurring inside the thread?

Thanks.

--Bradley


public class Main {
public static void main(String[] args) {
Thread thread = null;
for ( int intLoop = 0; intLoop < 10000; intLoop++ ) {
String myString;
myString = String.valueOf(1);
thread = new Thread() {
public void run() {
String str = String.valueOf(1);
}
};
thread.start();
thread=null;
System.gc();
}
}
}

Some things to consider:

1. IIRC System.gc() is just a hint. There is no guarantee that GC will
actually start at that moment.

2. There is no timely correlation between thread termination and
System.gc(), i.e. the string might not yet have been created when gc()
is invoked.

3. Generally the JVM is very free to decide when GC occurs. I doubt it
will create GC overhead if there is just a single (or a few) new objects
on the heap.

4. Your other examples do not exhibit the behavior you seem to observe
because they don't create new instances.

Kind regards

robert
 
B

BLlewellyn

Thomas said:
Are you sure you aren't just causing vast numbers of threads to be
running at once? Does shoving in a thread.join() fix it for you?

Tom Hawtin

Tom:

I have tried adding a thread.join() immediately after the
thread.start() method is called. The result is the same - according to
the NetBeans Profiler, none of the strings are being reclaimed. Any
more thoughts?

Thanks!

--Brad
 
B

BLlewellyn

Robert said:
If anyone could shed some light, I'd appreciate it.

I have a simple class with a main method. Inside the main method is a
loop. Each iteration of that loop instantiates an anonymous thread
whose run method contains a single line:

String str = String.valueOf(1);

This is causing a memory leak. If I change the line to read "String
str = "String.valueOf("1"); there is no problem. Also, if I do
something like: String str = "Hello world!"; there is also no problem.

If I use String.valueOf(1); inside the loop but outside of the thread,
there is no problem. Can anyone see why garbage collection is not
occurring inside the thread?

Thanks.

--Bradley


public class Main {
public static void main(String[] args) {
Thread thread = null;
for ( int intLoop = 0; intLoop < 10000; intLoop++ ) {
String myString;
myString = String.valueOf(1);
thread = new Thread() {
public void run() {
String str = String.valueOf(1);
}
};
thread.start();
thread=null;
System.gc();
}
}
}

Some things to consider:

1. IIRC System.gc() is just a hint. There is no guarantee that GC will
actually start at that moment.

2. There is no timely correlation between thread termination and
System.gc(), i.e. the string might not yet have been created when gc()
is invoked.

3. Generally the JVM is very free to decide when GC occurs. I doubt it
will create GC overhead if there is just a single (or a few) new objects
on the heap.

4. Your other examples do not exhibit the behavior you seem to observe
because they don't create new instances.

Kind regards

robert

Regarding number 1, using the NetBeans profiler, I'm seeing that each
thread is a live object right up to the end of the program. Not sure
if it will help, but according to the profiler there are 10,000 live
instances of the anonymous class (Main$1), and over 10,000 instances of
char arrays.

Because of number 2, I've tried using a thread.join() to make sure the
object is done being used.

3. The profiler is showing that time is being spent in GC - is it
possible that GC is running but decides the memory is not worth
reclaiming?

4. So basically you're saying that because String.valueOf("AString")
just returns a pointer, there's no string actually being created? That
makes sense.

I'm thinking that if I can get rid of the char[] reference that's
showing up in the profiler, the thread objects will go along with it.
Any idea what I can do to clear it?

Thanks again!

--Bradley
 
G

Gilbert Ostlethwaite

This is causing a memory leak. If I change the line to read "String
str = "String.valueOf("1"); there is no problem. Also, if I do
something like: String str = "Hello world!"; there is also no problem.

What version of the JVM are you using?

Regards
Roger
 
B

BLlewellyn

Gilbert said:
What version of the JVM are you using?

Regards
Roger

Roger:

Thanks for your reply. I have observed this on JVM 6 beta as well as
1.4.2. After getting nowhere with it, I decided to stop using the beta
JVM but it didn't change the result. I haven't tried 1.5.4 or 1.5.7
but I could if you think that might help.

Thanks.

--Bradley
 
R

Robert Klemme

Regarding number 1, using the NetBeans profiler, I'm seeing that each
thread is a live object right up to the end of the program. Not sure
if it will help, but according to the profiler there are 10,000 live
instances of the anonymous class (Main$1), and over 10,000 instances of
char arrays.

Well, then GC decided to not collect them.
Because of number 2, I've tried using a thread.join() to make sure the
object is done being used.

3. The profiler is showing that time is being spent in GC - is it
possible that GC is running but decides the memory is not worth
reclaiming?

Yes. There are some nice articles about how GC works on Sun's site. I
suggest you grab those and read through them - pretty interesting stuff.

GC is a quite complex process and the short story is that the JVM is
pretty free as to /when/ do GC and /which objects/ it will collect.
Especially will an object stay around even after a method terminated as
long as the stack frame is not overridden. This could be the case for
"myString" in run() because every thread gets its own stack.
4. So basically you're saying that because String.valueOf("AString")
just returns a pointer, there's no string actually being created? That
makes sense.
Exactly.

I'm thinking that if I can get rid of the char[] reference that's
showing up in the profiler, the thread objects will go along with it.
Any idea what I can do to clear it?

I have no idea what you mean here. The reference path is the other way
round, the char[] inside the String is referenced via the Thread.
Freeing the char[] or the String doesn't impact a thread's reachability
in any way. Note that threads are special and so the JVM might collect
them at different points in time than ordinary objects.

Cheers

robert
 
G

Gilbert Ostlethwaite

Thanks for your reply. I have observed this on JVM 6 beta as well as
1.4.2. After getting nowhere with it, I decided to stop using the beta
JVM but it didn't change the result. I haven't tried 1.5.4 or 1.5.7
but I could if you think that might help.

It's just that while investigating something else a couple of weeks ago
I came across a bug report that related to memory leaks, strings and
string buffers in 1.4.1. (Sorry I can't remember the details but it was
on the Sun bug site if you want to go find it) However I was under the
impression that it had been fixed in 1.4.2 :-( (Again, my memory may
be wrong).

Regards
Roger
 
B

BLlewellyn

Gilbert said:
It's just that while investigating something else a couple of weeks ago
I came across a bug report that related to memory leaks, strings and
string buffers in 1.4.1. (Sorry I can't remember the details but it was
on the Sun bug site if you want to go find it) However I was under the
impression that it had been fixed in 1.4.2 :-( (Again, my memory may
be wrong).

Regards
Roger

Ok...thanks for the lead. I will follow-up with that. It's all I got
right now :)

--Brad
 
T

Thomas Kellerer

If anyone could shed some light, I'd appreciate it.

I have a simple class with a main method. Inside the main method is a
loop. Each iteration of that loop instantiates an anonymous thread
whose run method contains a single line:

String str = String.valueOf(1);

This is causing a memory leak. If I change the line to read "String
str = "String.valueOf("1"); there is no problem. Also, if I do
something like: String str = "Hello world!"; there is also no problem.

If I use String.valueOf(1); inside the loop but outside of the thread,
there is no problem. Can anyone see why garbage collection is not
occurring inside the thread?

This is strange.

String.valueOf(int) gets dispatched to Integer.toString(int) which has a
special treatment for some values. In your case it directly returns the
literal "1"

public static String toString(int i) {
switch(i) {
case Integer.MIN_VALUE: return "-2147483648";
case -3: return "-3";
case -2: return "-2";
case -1: return "-1";
case 0: return "0";
case 1: return "1";
case 2: return "2";
case 3: return "3";
case 4: return "4";
case 5: return "5";
case 6: return "6";
case 7: return "7";
case 8: return "8";
case 9: return "9";
case 10: return "10";
}
.....

So the memory leak might be somewhere else.
Maybe inside the Thread class?

Regards
Thomas
 

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,266
Messages
2,571,082
Members
48,773
Latest member
Kaybee

Latest Threads

Top