使用Thread分配内存

时间:2012-05-11 15:44:45

标签: java multithreading memory-management

我想知道如果在方法中声明本地线程会发生什么?通常,函数返回后,所有局部变量都将消失,因为它们都在Stack上分配。然而,似乎本地线程将是一个不同的故事。是对的吗?

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

5 个答案:

答案 0 :(得分:14)

线程是它自己的GC根。因此,无论何时创建线程,无论其创建上下文如何,在其运行方法完成之前,它都不会准备好GC。即使本地方法完成且线程仍处于活动状态,也是如此。

示例:

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

//do somethign else quickly任何未转义的定义后,该方法将被标记为GC。线程th不会被标记为GC,并且正确地放置在具有自己的线程堆栈的堆上。

答案 1 :(得分:7)

约翰的答案很好,但我想我会补充一些细节。这是一个代码示例,我将用它来显示特定的变量用法。

 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();
 }

因此我们在线程周围分配了许多变量。我们还有Thread对象本身以及线程正在运行的Runnable目标。

  • thread - 虽然它看起来是startThread()的本地,但关联的Thread也由JVM管理。在run()方法完成并且Thread由JVM获取后,它只是GC'd。 Thread为GC后,Thread使用的所有字段都可以进行GC。
  • Runnable - 这个匿名类是线程正在运行的。它可以在Thread完成后进行GC并且是GC。
  • var1 - 这是startThread()的本地,并在堆栈上分配。当startThread()方法完成并重复使用堆栈时,它将被覆盖。
  • var2 - 这是startThread()的本地,并在堆上分配。它不能被线程使用,因为它不是final。它可以在startThread()完成后进行GC。
  • var3 - 这是startThread()的本地,并在堆上分配。这是final因此线程可以使用 ,但事实并非如此。它可以在startThread()完成后进行GC。
  • var4 - 这是startThread()的本地,并在堆上分配。这是final,它由线程使用。在startThread()方法完成 Runnable并且Thread都是GC后,它只能是GC。
  • var5 - 这是Runnable内部的本地字段,并作为Runnable匿名类的一部分在堆上分配。在Runnable完成后RunnableThread为GC后,可以进行GC。
  • var6 - 这是Runnable内的一个本地字段,并在堆上分配。在Runnable完成后RunnableThread为GC后,可以进行GC。
  • var7 - 这是run()方法内部的本地字段,并在新线程的堆栈上分配。当run()方法完成并重复使用堆栈时,它将被覆盖。
  • var8 - 这是run()方法中的本地字段,并在堆上分配。在run()方法完成后,它可以是GC。
  • var9 - 这是baz()方法内部的本地字段,并在新线程的堆栈上分配。当baz()方法完成并重复使用堆栈时,它将被覆盖。
  • var10 - 这是baz()方法内部的本地字段,并在堆上分配。在baz()方法完成后,它可以是GC。

结合其他笔记:

  • 如果新线程从未启动过,则startThread()完成后可以进行GC。 Runnable以及与之关联的所有变量也可以是GC。
  • 如果在final long varX中声明了startThread()原语并在线程中使用,那么它必须在堆上分配而堆栈。当startThread()完成后,它仍然会被使用。

答案 2 :(得分:0)

如果从本地上下文启动Thread,则该线程将继续执行,直到Runnable的run方法已完成执行。

答案 3 :(得分:0)

如果变量是基元,那么它将在堆栈上并且在方法返回时将消失 - 但是你的线程的Runnable实例(或包含线程内容的任何内容)将具有原始值的副本。

如果变量属于引用类型,则该对象在堆上分配并存在,直到不再有对它的引用为止,此时它有资格进行垃圾回收。该对象的引用在堆栈上,并且在方法返回时将消失,但与原语一样,线程的Runnable将具有该相同引用的副本(并因此将保留那个对象活着)。

答案 4 :(得分:-1)

如果在方法中生成本地Thread,则只有声明为final的本地方法变量才会保留,直到Thread完成。当Thread完成其run()方法时,线程及其从创建它的方法可用的任何最终变量将像其他所有内容一样被垃圾收集。

<强>澄清

在方法和final方法完成之前,原始方法中使用的只有run()个变量和生成的线程的run()方法将避免被垃圾回收。如果线程没有访问变量,那么线程的存在将不会阻止变量在原始方法完成后被垃圾收集。

<强>参考

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