2012-05-11 12 views
3

メソッド内にローカルスレッドを宣言するとどうなりますか?通常、すべてのローカル変数は、スタックにすべて割り当てられているので、関数が返るとすぐになくなります。しかし、ローカルスレッドは別の話になるようです。そうですか?スレッドでのメモリ割り当て

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

この質問は読みにくい/理解しています。それを肉体に編集できますか?あなたが求めていることをよりよく説明してください。簡潔に表示してください。コードサンプル? – Gray

答えて

13

スレッドは独自のGCルートです。したがって、作成コンテキストにもかかわらずスレッドを作成するたびに、runメソッドが完了するまでは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後。スレッドthはGC用にマークされず、ヒープ上に正しくスレッドスタックされて配置されます。

+0

+1ニースの答えのジョン。詳細なサンプルコードを表示できますか? – Gray

+0

ローカルスレッドがメソッド内でローカルとして宣言されていても、ヒープ上に配置されることを意味しますか? – peter

+0

@ user1389813 Javaはエスケープ解析を行い、オブジェクトをスタック上またはヒープ上にローカルに配置できるかどうかを判断します。スレッドは本質的にエスケープし、ヒープ上に配置されます。ここでエスケープ解析を読むことができます。http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html –

0

スレッドはローカルコンテキストから開始された場合は、スレッドがRunnableのrunメソッドが実行を完了したのですまで実行を継続します。

-1

メソッド内にローカルThreadをスポーンする場合、Threadが完了するまでfinalと宣言されたローカルメソッド変数のみが固執します。 Threadrun()メソッドを完了すると、スレッドとそれを作成したメソッドから利用可能な最終変数は、他のすべてと同様にガベージコレクションされます。元のメソッドと生成されたスレッドのrun()メソッド内で使用

明確化

のみfinal変数は、メソッドとrun()方法の両方が完了するまでゴミが収集されてから控えます。スレッドが変数にアクセスしない場合、スレッドの存在は、元のメソッドが完了した後に変数がガベージコレクションされるのを妨げません。

参照

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

+0

が、スタックまたはヒープ上のローカルスレッドですか? – peter

+1

ファイナルは、フィールドが「つぶれている」かどうかは関係ありません。ファイナルは、フィールドを再割り当てできるかどうかに影響し、コンストラクタの割り当て順序にも影響します。 – Gray

+1

それは確かです。メソッドの先頭に最終変数を宣言するメソッドがある場合、run()メソッド内でその最終変数にアクセスするスレッドが生成され、スレッドがまだ実行されている限り、最終変数はガベージコレクションされません。なぜなら、その最終変数はスレッドによってJVMのオブジェクトグラフに到達可能であるからです。これは、スレッドを生成した元のメソッドがrun()メソッドの前に戻るかどうかにかかわらず、trueです。 – CodeBlind

0

変数がプリミティブである場合、それはスタック上になるだろうとメソッドが返すときに消えてしまいます - しかし、あなたのスレッドのRunnableインスタンス(またはものは何でもスレッドの肉を含んでいる)はそのプリミティブ値のコピーを持ちます。

変数が参照型である場合、オブジェクトはヒープ上に割り当てられ、参照がなくなるまで生き残ります。その時点でガベージコレクションの対象となります。そのオブジェクトへの参照はスタック上にあり、メソッドが戻るときにはなくなりますが、プリミティブと同様に、スレッドのRunnableはその同じ参照のコピーを持ちます(したがってそのオブジェクトは生き続けるでしょう)。

+0

メソッド内で宣言されたプリミティブ変数がスタックに格納されます。クラスのフィールドであるプリミティブ変数は、ヒープ上にあります。 – Gray

+0

@Grayはい、フィールド以外の変数を指定する必要があります。私はクラス/インスタンス変数を "フィールド"と呼んでそのあいまいさを減らす傾向があります。それはまれではないと思いますが、厳密にはJLSではないと私は同意します。 – yshavit

6

ジョンの答えは良いですが、私はもう少し詳しく説明したいと思いました。

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ターゲットがあります。

  • スレッド - それはstartThread()にローカルになりそうだが、関連するThreadもJVMによって管理されています。 run()メソッドが終了し、ThreadがJVMによって取得された後にのみGCされます。 ThreadがGC'dの後に、Threadによって使用されるすべてのフィールドはGC'dになります。
  • Runnable - この匿名クラスは、スレッドが実行しているものです。 Threadの処理が完了した後にGCしてGCすることができます。
  • var1 - startThread()にローカルであり、スタックに割り当てられています。 startThread()メソッドが終了し、スタックが再利用されると上書きされます。
  • var2 - これはstartThread()にローカルであり、ヒープに割り当てられます。 finalではないため、スレッドで使用することはできません。 startThread()の終了後にGCすることができます。
  • var3 - これはstartThread()にローカルであり、ヒープに割り当てられます。これはfinalですので、スレッドで使用できますが、そうではありません。 startThread()の終了後にGCすることができます。
  • var4 - これはstartThread()にローカルであり、ヒープに割り当てられます。これはfinalであり、スレッドによって使用されます。 startThread()のメソッドが終了した後にのみGCすることができます。RunnableThreadはGCです。
  • var5 - Runnableのローカルフィールドで、匿名クラスRunnableの一部としてヒープに割り当てられます。 Runnableの終了後にGCし、RunnableThreadをGCすることができます。
  • var6 - これはRunnableの内部のローカルフィールドであり、ヒープに割り当てられます。 Runnableの終了後にGCし、RunnableThreadをGCすることができます。
  • var7 - これはrun()メソッドの内部のローカルフィールドで、新しいスレッドのスタックに割り当てられます。 run()メソッドが終了し、スタックが再利用されると上書きされます。
  • var8 - これはrun()メソッド内のローカルフィールドであり、ヒープに割り当てられます。 run()メソッドの終了後にGCすることができます。
  • var9 - これは、baz()メソッドの内部のローカルフィールドであり、新しいスレッドのスタックに割り当てられます。 baz()メソッドが終了し、スタックが再利用されると上書きされます。
  • var10 - これはbaz()メソッド内のローカルフィールドであり、ヒープに割り当てられます。 baz()メソッドの終了後にGCすることができます。

カップルその他の注意事項:

  • 新しいスレッドは、それがstartThread()終了後GC'dすることができます開始されることはありません場合。 Runnableと、それに関連するすべての変数は、同様にGCすることができます。
  • startThread()で宣言されたfinal long varXプリミティブがスレッドで使用されている場合は、ヒープに割り当てられ、ではなく、スタックに割り当てられている必要があります。startThread()が終了すると、まだ使用されます。
+0

var 9が割り当てられますその匿名スレッドのスタック、正しい?各スレッドは独自のスタックを持ちますが、同じヒープを共有しています。また、内側のクラス(匿名クラス)が外側スコープの変数にアクセスするためには、変数をfinalとして宣言することが唯一の方法です。 – peter

+0

はい、var9は新しいスレッドのスタックにあります。 var7と同じです。私はそれをもっと明確にするために私の答えを編集しました@ user1389813。 – Gray

+0

新しいスレッドが決して始まらない場合はどうすればいいですか? – peter