peter
peter

Reputation: 8473

Memory allocation with Thread

I am wondering what happen if you declare a local thread within a method? Normally all the local variables will be gone as soon as the function returns since they are all allocated on Stack. However, it seems that a local thread would be a different story. Is that right?

public int A() {
    Thread t = new Thread() {
        doSomething();
    }
    t.start();
    return -1;
 }

Upvotes: 3

Views: 6031

Answers (5)

Gray
Gray

Reputation: 116918

John's answer is good but I thought I'd add some more details. Here's a code example that I'll use to show specific variable usage.

 public void startThread() {
      long var1 = 10;
      byte[] var2 = new byte[1024];
      final byte[] var3 = new byte[1024];
      final byte[] var4 = new byte[1024];
      Thread thread = new Thread(new Runnable() {
          private long var5 = 10;
          private byte[] var6 = new byte[1024];
          public void run() {
              int var7 = 100;
              byte[] var8 = new byte[1024];
              System.out.println("Size of var4 is " + var4.length);
              baz();
              ...
          }
          private void baz() {
              long var9 = 2;
              byte[] var10 = new byte[1024];
              ...
          }
      });
      thread.start();
 }

So we have a number of variables here allocated around a thread. We also have the Thread object itself as well as the Runnable target the thread is running.

  • thread -- Although it looks to be local to startThread(), the associated Thread is also managed by the JVM. It is only GC'd after the run() method finishes and the Thread is reaped by the JVM. After the Thread is GC'd then all of the fields used by the Thread can be GC'd.
  • Runnable -- This anonymous class is what the thread is running. It can be GC'd after the Thread finishes and is GC'd.
  • var1 -- This is local to startThread() and allocated on the stack. It will be overwritten when the startThread() method finishes and the stack is reused.
  • var2 -- This is local to startThread() and allocated on the heap. It cannot be used by the thread since it is not final. It can be GC'd after startThread() finishes.
  • var3 -- This is local to startThread() and allocated on the heap. This is final so it could be used by the thread but it is not. It can be GC'd after startThread() finishes.
  • var4 -- This is local to startThread() and allocated on the heap. This is final and it is used by the thread. It can only be GC'd after both the startThread() method finishes and the Runnable and the Thread are GC'd.
  • var5 -- This is a local field inside of the Runnable and allocated on the heap as part of the Runnable anonymous class. It can be GC'd after the Runnable finishes and the Runnable and the Thread are GC'd.
  • var6 -- This is a local field inside of the Runnable and allocated on the heap. It can be GC'd after the Runnable finishes and the Runnable and the Thread are GC'd.
  • var7 -- This is a local field inside of the run() method and allocated on the stack of the new thread. It will be overwritten when the run() method finishes and the stack is reused.
  • var8 -- This is a local field inside of the run() method and allocated on the heap. It can be GC'd after the run() method finishes.
  • var9 -- This is a local field inside of the baz() method and allocated on the stack of the new thread. It will be overwritten when the baz() method finishes and the stack is reused.
  • var10 -- This is a local field inside of the baz() method and allocated on the heap. It can be GC'd after the baz() method finishes.

Couple other notes:

  • If the new thread is never started then it can be GC'd once startThread() finishes. The Runnable and all of the variables associated with it can be GC'd then as well.
  • If you have a final long varX primitive declared in startThread() and used in the thread, then it must be allocated on the heap and not the stack. When startThread() finishes it will still be in use.

Upvotes: 7

CodeBlind
CodeBlind

Reputation: 4569

If you spawn a local Thread within a method, only the local method variables declared as final will stick around until the Thread has completed. When the Thread completes its run() method, the thread and any final variables it had available to it from the method that created it will get garbage collected like everything else.

Clarification

Only final variables used within the original method AND the spawned Thread's run() method will refrain from being garbage collected until both the method and the run() method completes. If the thread doesn't access the variable, then the presence of the thread will not prevent the variable from being garbage collected after the original method completes.

References

http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html

Upvotes: -1

John Vint
John Vint

Reputation: 40266

A Thread is its own GC root. So any time you create a thread despite its creation context it will not be ready to GC until its run method completes. This is true even if the local method completes and the thread is still alive.

Example:

public void doSomeAsync(){
   Thread th = new Thread(new Runnable(){
      public void run(){
          Thread.sleep(500);
      }
   });
   th.start();
   //do something else quickly
}

After //do somethign else quickly anything defined that did not escape the method is then marked for GC. Thread th will not be marked for GC and is correctly placed on the heap with it's own thread-stack.

Upvotes: 14

yshavit
yshavit

Reputation: 43401

If the variable is of a primitive, then it'll be on the stack and will be gone when the method returns -- but your thread's Runnable instance (or whatever contains the meat of the thread) will have a copy of that primitive value.

If the variable is of a reference type, then the object is allocated on the heap and lives until there are no more references to it, at which point it's eligible for garbage collection. The reference to that object is on the stack and will be gone when the method returns, but as with primitives, the thread's Runnable will have a copy of that same reference (and will thus keep that object alive).

Upvotes: 0

FThompson
FThompson

Reputation: 28707

If a Thread is started from a local context, the thread will continue to execute until it's Runnable's run method has completed execution.

Upvotes: 0

Related Questions