Duplicate :
|
|
Duplicate :
|
Name: yyT116575 Date: 09/27/2001 java version "1.3.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0) Java HotSpot(TM) Client VM (build 1.3.0, mixed mode) In our experiments with Jtella (Gnutella servent in Java) we noted that Threads were getting lost. We were printing out "activeCount" and using "enumerate" to list existing threads. The numbers did not match and the discrepancy would increase with time.... and eventually the program would run out of memory. The enclosed mini program illustrates the problem and We now know why it happens. Basically, Java Threads that are not "started" are never garbage collected. In UNIX, we speak of Zombie (walking dead) processes that are dead but still use resources. Here in Java, we have the same thing at the other end of the life cycle: walking unborn Threads. We understand that "active" Threads should not be garbage collected even if there are unreachable from the MAIN program; however once a Thread is no longer alive (has returned from its "run" method); it should be fair game. The problem lies with Threads that have been created but not "started". If the user has no reference to them; there is no way he can "start" them so that they will terminate: they are not yet alive but are not dead. Looking at the source code for ThreadGroup, we suspect that they unborn Threads have pointers in the Group Thread Table - so that they are not garbage collected. Because "enumerate" only returns references to "alive" threads, we can't get at them that way. Example: // AliveTest.java: program to test theory that Threads which are not started // are not garbage collected // - We create "T" Threads but don't "start" them. The output shows: // a) that creation is fast (compared to -starting- Threads) // b) that memory is garbage collected // c) the Thread ACTIVE count always increases // d) eventually we run out of memory public class AliveTest { public static void main (String [] args) { long t1 = System.currentTimeMillis(); Runtime r = Runtime.getRuntime(); for (int i = 1; ; i++) { // new T().start(); new T(); if (i%100==0) { System.out.println ("Threads created: " + i + ", t: " + (System.currentTimeMillis()-t1)/1000 + " sec, activeCount: " + Thread.activeCount() + ", Free mem:" + r.freeMemory()/1000 + " K"); } } } } class T extends Thread { int [] a = new int [10000]; public void run() { a[0] = 1; } } /* ----------------------------- Output --------------------------- mere> java AliveTest Threads created: 100, t: 0 sec, activeCount: 101, Free mem:2261 K Threads created: 200, t: 0 sec, activeCount: 201, Free mem:2726 K Threads created: 300, t: 0 sec, activeCount: 301, Free mem:6120 K Threads created: 400, t: 0 sec, activeCount: 401, Free mem:2107 K Threads created: 500, t: 0 sec, activeCount: 501, Free mem:9602 K Threads created: 600, t: 0 sec, activeCount: 601, Free mem:5580 K Threads created: 700, t: 0 sec, activeCount: 701, Free mem:1567 K Threads created: 800, t: 0 sec, activeCount: 801, Free mem:16968 K Threads created: 900, t: 0 sec, activeCount: 901, Free mem:12955 K Threads created: 1000, t: 0 sec, activeCount: 1001, Free mem:8936 K Threads created: 1100, t: 0 sec, activeCount: 1101, Free mem:4914 K Threads created: 1200, t: 0 sec, activeCount: 1201, Free mem:895 K Threads created: 1300, t: 1 sec, activeCount: 1301, Free mem:13474 K Threads created: 1400, t: 1 sec, activeCount: 1401, Free mem:9455 K Threads created: 1500, t: 1 sec, activeCount: 1501, Free mem:5436 K Threads created: 1600, t: 1 sec, activeCount: 1601, Free mem:1422 K Exception in thread "main" java.lang.OutOfMemoryError <<no stack trace available>> ---------------------------------------------------------------------- */ (Review ID: 132751) ======================================================================