I’m almost certain that’s incorrect behaviour, as a Thread is an Object like any other and should be collectable once there are no strong references to it any more. Unless invokeLater() is keeping hold of them…?
Cas
I’m almost certain that’s incorrect behaviour, as a Thread is an Object like any other and should be collectable once there are no strong references to it any more. Unless invokeLater() is keeping hold of them…?
Cas
I’m with cas, unless you can demonstrate that creating threads objects and overriding their run method for use in an invokeLater() call does NOT let the object get GC’d. Runnable just says your class must implement a method named run(). Threads have nothing to do with it. invokeLater() is just using the appropriate interface for clients to implement if they want some action performed later.
The Swing event thread should remove references to any object that was ‘registered’ with it to invoke later via the invokeLater() call. If the object isn’t being GC’d there’s another reference to the object somewhere.
-Chris
Regarding SWT: While I’m a big fan of SWT, I don’t really see how this framework would help developing game GUIs.
[]You can’t use it for applets.
[]You can’t go “full screen” or change the display mode.
[]You get these “boring” native controls (a good thing for business application but let’s say for a fantasy RPG I’d like to see some medieval-looking UI).
[]Drawing performance isn’t always better.
On Windows, drawing on an SWT canvas seems to be a little bit faster than drawing on an AWT canvas as it directly uses GDI calls and has a better damage redraw strategy. It’s however not faster than Java2D calls which might use a lower level hardware accelerated API. On Linux, SWT seems to draw noticable slower than pure Java.
Whatever, some ideas:
One could of course create own custom drawn buttons, input fields, list boxes, etc. with any skin you could possible want (I’d even call this easy to do). Unfortunately, SWT’s drawing capabilities are primitive compared to the 2D API. There’s for example no easy way to do transparency and no way I know to load a custom font. On the other hand, you have full access to all platform fonts and platform font rendering like subpixel antialiasing.
If you don’t care about using the lower level AWT methods, namely the Java2D API, you could combine its power with SWT. This might the best way to go but it requires Java 2. If you can live without advanced 2D graphics, you could use gcj to compile an executable.
Another interesting idea might be to combine something like the LWGL with SWT. I’d assume that LWGL eventually draws upon a Windows GC. This is directly exposed in SWT so you could probably efficiently combine 3D hardware accelerated graphics with SWT.
This is something a lot of people might be interested in IIRC the comments on the eclipse.tools newsgroup. I’ve however no knowledge about 3D and can’t estimate whether such a combo would be difficult.
Stefan
I have never found Swing and AWT widgets all that exciting either.
Are you using SWT for Motif or GTK? Java AWT components always use Motif. I might be wrong here but I think Motif is faster then GTK at rendering widgets due to the GTK being several layers further from X-Windows compared to Motif (all that skinning stuff has to hurt performance too). I think the Motif side of SWT will become deprecated some day though.
There are ways to get Java 2D in SWT:
I have never tried it but it looks interesting.
At last I checked GCJ has no widget set at all.
I can see that.
If you want pure performance and no frills, use pure LWJGL.
If you want to mix a Java GUI with high-performance OpenGL, use GL4Java and AWT or Swing.
If you want plain old 2D for games or applets, stick to AWT and Java2D. Use Swing if you want nicer controls.
If you want to write productivity applications then SWT will probably work just as well as AWT.
Cas
I’m with cas, unless you can demonstrate that creating threads objects and overriding their run method for use in an invokeLater() call does NOT let the object get GC’d.
You and Cas are missing the point. SwingUtilities.invokeLater() only asks for a Runnable, because it’s not going to create a new thread - it’s just going to execute the Runnable on the event thread. Subclassing Thread, in this case, gains you no advantages whatsoever and is extremely gratuitous at best, especially considering that it is directly associated with heavyweight operating system resources - which is probably why Thread objects aren’t garbage collected until after the native operating system thread has been started and finished executing (at least on the VMs I have worked with). Don’t believe me? Run this code:
import java.io.*;
public class ThreadTest {
public static void main( String[] args ) throws Exception {
final int total = 1000;
for ( int i = 0; i < total; ++i ) {
Runnable r = new Runnable() {
public void run() {
}
public void finalize() {
System.out.println( "Runnable finalized." );
}
};
}
for ( int i = 0; i < total; ++i ) {
Thread t = new Thread() {
public void run() {
}
public void finalize() {
System.out.println( "Thread finalized." );
}
};
// t.start()
}
BufferedReader r = new BufferedReader( new InputStreamReader( System.in ) );
while ( true ) {
System.out.println( "Enter \"gc\" to garbage collect or \"q\" to quit." );
String command = r.readLine();
if ( command == null ) {
continue;
}
command = command.trim();
if ( command.equals( "q" ) ) {
break;
}
else if ( command.equals( "gc" ) ) {
System.out.println( "Garbage collected." );
System.gc();
}
else {
System.out.println( "Command not understood." );
}
System.out.println();
}
}
}
You’ll see the Runnables are all collected, but the Threads will never be collected, no matter how many times you request GC and how long you wait. Stick a t.start() in there, and all of the sudden all of your Threads will get collected.
God bless,
-Toby Reyelts
No, we’re not missing the point. The Threads should be garbage collected, and if they aren’t, it’s a bug, or a contradiction in the specification.
And the contract of invokeLater is that it takes a Runnable, and therefore it should be no problem to pass it anything I like that implements a Runnable. It might happen to be a Thread.
Cas
No, we’re not missing the point.
Cas, you’re just like Chris. Talking to you guys is like talking to a brick wall. You both can just be so thick.
God bless,
-Toby Reyelts
Ok, we all know an Object isn’t collected unless it isn’t “strongly” reachable. Well if you work your way back up to the top of the Object hierarchy what do you find? You’ll find a Thread object.
You can start a Thread and release any strong references to it and as long as it is running it will not be garbage collected. This makes sense as you don’t want a running thread to disappear on you even if you don’t keep strong references. (Cas: In a running state this makes it different than any other Object.) Once a Thread is done and there are no strong references it is collected as normal.
What doesn’t make sense to me is a Thread that is no longer strongly reachable and hasn’t been start()ed isn’t collected. Below is a program that demonstrates this. My only explination is that an un-start()ed Thread is considered to be the root of an object hierarchy and thus not collectable. To me Cas is right that un-start()ed Thread objects should be collected as normal because if they are not referenced then there is no way for the start() method to be called.
class Go {
public static void main(String[] args) {
int count = 0;
while (true) {
count++;
Thread t = new Thread();
// t.start(); // Uncomment and it will never run out of memory
if (count == 10000) {
System.gc();
System.out.println("Free Memory: "
+ Runtime.getRuntime().freeMemory());
count = 0;
}
Thread.yield();
}
}
}
Personally I’m not sure if this is a bug but I’m not convinced it’s not a bug either. I’d really like a link to an explaintaion or one of the Sun guys to comment on this.
I was joking. I agree, AWT doesn’t look exciting, especially not on Linux. With Swing however, one can easily create custom looks which could look nice and exciting.
I was referring to SWT for GTK+ 2.0. The Motif version might be faster (I think, you could also replace Motif with Lesstif but don’t know which one is faster) but the Motif look out of the box is ugly. I don’t think, SWT for Motif will die soon, the Solaris and especially the AIX version of Eclipse depends on it.
Stefan
Aha, my trolling friend, it seems Leknor has explained for you why this should be the case more clearly. It is an ambiguous behaviour and it’s certainly undocumented and ought to be fixed as you can break a VM irrevocably in this way.
Cas
[quote]If you want pure performance and no frills, use pure LWJGL.
[/quote]
Will LWJGL open and manage its own windows? Can I set caption text, min/max/buttons, what’s about (modal) dialogs? Browsing over the doc (only a few seconds I admit) I didn’t find this functionallity.
Cas, why do you think that SWT wouldn’t be an option to be mixed with LWGL. I thought, that your library would be kind-of a replacement for GL4Java, some way to get accelerated graphics for Java. Having some “traditional” GUI framework might help to speed up development.
Or let me ask a different question: Let’s say I’d like to create something like the original Warcraft or Battle Isle (both not requiring fancy 3D graphics) game. What would be the best approach in Java. Let’s further say, Windows is the most important platform and Linux would be a nice to have.
Definitely better than AWT. Not so sure about Swing though. Here it depends on your requirements which one has more advantages.
Stefan
LWJGL is a replacement for the entire windowing feature of an OS. It turns your PC into a “console”, with a screen, speakers, and some input devices, and that’s just about all. As such it doesn’t integrate with any notion of a windowing system, so SWT and AWT are redundant. You have to write your own - I have, it took about a month to make it perfect. Various others have experimented with writing realtime rendered GUIs too, all with great success. It’s a lot easier than it looks.
If you’re creating Warcraft in Java then I suspect that a system with enough poke to run Java will probably also be modern enough to have an OpenGL compatible card so I’d go for LWJGL myself But these days the AWT with its new VolatileImage is producing simple graphics at full speed, if a little buggily. I prefer GL because it lets me scale, rotate, and blend sprites with no noticeable performance degradation.
Although I am wondering whether we need a special 2D interface into LWJGL because there’s some plenty fast cards out there that basically have broken OpenGL drivers and don’t work as advertised, or for a lot of laptops there is no GL but there’s speedy 2D, and that’s quite annoying for 2D only stuff.
I’m going to open a thread on 2D in LWJGL.
Cas
Aha, my trolling friend…
Lol, you invoked the “troll-net”, because I demonstrated the relevant problem with threads that you just don’t seem to get. That’s amusing. I know you hate to admit you’re wrong to KevDog, but isn’t this pushing it?
it seems Leknor has explained for you why this should be the case more clearly.
Leknor didn’t demonstrate anything beyond which I already said.
It is an ambiguous behaviour and it’s certainly undocumented and ought to be fixed as you can break a VM irrevocably in this way.
It’s a bug in the VM, you yahoo. If you would take the 30 seconds, you could find it in the bug database. As to how you can “break” a VM with this bug, I don’t know. You can certainly leak memory to your heart’s content - which is the point KevDog was trying to make.
All of this doesn’t address the fact, that it is entirely superfluous and wrong-headed to subclass Thread to implement the Runnable interface for SwingUtilities.invoke*. If you can’t see that, there is little hope for you.
God bless,
-Toby Reyelts
rreyelts, will you learn to stfu and READ a post for once? Did you notice in my post I said:
And then you go on to say in response:
We are saying the same thing with respect to invokeLater(), which is you only need to pass it a referenence to a Runnable object wich should be garbage collected afterwards. Threads have been shown to hang around in the VM without starting them, Whoopiee! Give that man a medal.
The only explanation for this behavior i can determine is that start() will perform some cleanup after the run() method returns. I imagine other peer-dependent objects that are created but not used (sockets? windows?) will also exhibit this behavior because they need an explicit call to a cleanup methods (such as dispose() or something) to have the peer released. Moral of the story here is don’t create threads you don’t use.
I think the implementation of thread is flawed, it shouldn’t create any peer-level objects (os threads) until start() is called (less chance of objects being orphaned). but, i guess it makes thread pooling faster if peer-level objects are created at instantiation time instead of at start time.
-Chris
will you learn to stfu
Profanity - wonderful.
and READ a post for once?
Here’s some quoting to satisfy you Chris. (I thought I already did that enough, but apparently not for your tastes).
Cas: Er, Kevdog, Thread is a Runnable - I suggest you go and find out what the bug is in your code and change your advice!
Herkules: Yes, but a Runnable is not a Thread. And a Runnable is sufficient. So kevdogs advice is deeply true
KevDog: Yep, a Thread is a Runnable, but a Runnable is not a Thread Thread has a lot more overhead.
So, what we see here is Cas telling KevDog that he’s written buggy code. KevDog explains that his code is not buggy and he and Herkules both make the point that Thread has more overhead than Runnable - it should therefore not be used in preference to directly implementing Runnable.
I think everybody gets the point, so I’m done.
God bless,
-Toby Reyelts
It’s buggy code all right but it’s not Kev’s fault, it turns out… I should go back and edit my message but then it breaks your quote No worries now, calm down etc.
Cas
Wow, don’t get too worked up
Guess we’re all passionate about Java
My main point was don’t use Thread or a subclass of Thread for the invoke functions.
Threads become active when they are created (with new) and not when they are started (you can run Thread.activeCount() after creating a new one). Active threads are not garbage collected, so if you never run start() they will never be garbage collected. Whether this is a bug in the JVM or not, I don’t know (and don’t want to read the JVM spec to find out ) but that’s the way it currently is.
When I first encountered this, I thought it was a JVM bug in JDK 1.1.8 (we’re a bit behind the times!). I tried a sample on JDK 1.4.0 and it still had the same behaviour, so I assumed it wasn’t a bug and was just the way it works.
I changed all the Thread subclasses to Runnable subclasses and all the thread leaks went away. We no longer have 10,000-50,000 threads hanging around in memory unrun.
You guys should read Thread.java distributed with any JDK from SUN. It clearly shows that after creation, a thread will be added to a ThreadGroup. Only after start() is called, the private exit() will be called from native part. exit() removes the thread from the ThreadGroup which makes the thread garbage collectable.
Construction of a Thread() with no parameters, it says in the JDK docs, is the same as passing null as the threadgroup, so it shouldn’t be referenced by any ThreadGroup. It’s a hole that needs patching all right.
Cas