2012-05-11 6 views
3

메서드 내에서 로컬 스레드를 선언하면 어떻게 될까요? 일반적으로 모든 지역 변수는 스택에 모두 할당되기 때문에 함수가 리턴하자 마자 사라질 것입니다. 그러나 로컬 스레드가 다른 스토리가 될 것으로 보입니다. 그게 맞습니까?스레드를 사용한 메모리 할당

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

이 질문은 읽기/이해하기 어렵습니다. 당신은 그것을 육체로 편집 할 수 있습니까? 당신이 묻고있는 것을 더 잘 설명하십시오. 간결하게 보여주십시오. 코드 샘플? – Gray

답변

13

스레드는 자체 GC 루트입니다. 따라서 생성 컨텍스트에도 불구하고 스레드를 만들면 run 메서드가 완료 될 때까지 GC에 준비가되지 않습니다. 로컬 메소드가 완료 해 thread가 아직 생존하고 있어도, 이것은 사실입니다.

예 : 방법을 탈출하지 않았다 아무것도 정의는 다음 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

결승전은 필드가 "주변에 매달려 있는지"와 관련이 없습니다. Final은 필드를 재 할당 할 수 있는지 여부와 생성자 할당 순서에 영향을 미칩니다. – Gray

+1

물론 있습니다. 메서드의 맨 위에 최종 변수를 선언하는 메서드가있는 경우 run() 메서드 내에서 해당 최종 변수에 액세스하는 스레드를 생성하고, 스레드가 실행되는 동안 최종 변수는 가비지 수집되지 않습니다. 왜냐하면 그 최종 변수는 스레드에 의해 JVM의 객체 그래프에서 여전히 도달 할 수 있기 때문입니다. run() 메서드 이전에 스레드를 생성 한 원래 메서드가 반환하는지 여부에 관계없이 true입니다. – CodeBlind

0

-하지만 스레드의 Runnable 예 (또는 무엇이든 스레드의 고기 포함)에는 해당 원시 값의 사본이 있습니다.

변수가 참조 유형 인 경우 개체는 힙에 할당되어 참조가 없어 질 때까지 가비지 수집에 적합합니다. 해당 객체에 대한 참조은 스택에 있으며 메소드가 반환 될 때 사라지지만 프리미티브와 마찬가지로 스레드의 Runnable에는 동일한 참조 사본이 있으므로 해당 객체가 계속 유지됩니다.

+0

메소드 내부에서 선언 된 기본 변수가 스택에 있습니다. 클래스의 필드 인 기본 변수는 힙에 있습니다. – Gray

+0

@ 그레이 예, 필드가 아닌 변수를 지정해야합니다. 그 모호성을 줄이기 위해 클래스/인스턴스 변수를 "필드"라고 부르는 경향이 있으며, 드문 일이 아니지만 엄격하게 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 할 수 있습니다.
  • Runnable -이 익명 클래스는 스레드가 실행되고있는 클래스입니다. Thread 완료 후에 GC 할 수 있으며 GC로 처리됩니다.
  • var1 - startThread()에 국부적으로 할당되어 스택에 할당됩니다. startThread() 메서드가 완료되고 스택이 다시 사용될 때 덮어 씁니다.
  • var2 - 이것은 startThread()에 국부적이고 힙에 할당됩니다. final이 아니기 때문에 스레드에서 사용할 수 없습니다. startThread() 완료 후에 GC 할 수 있습니다.
  • var3 - 이것은 startThread()에 국부적이고 힙에 할당됩니다. 이것은 final이므로 이 스레드에서 사용되지만 그렇지 않습니다. startThread() 완료 후에 GC 할 수 있습니다.
  • var4 - 이것은 startThread()에 국부적이고 힙에 할당됩니다. 이것은 final이며 스레드에 의해 사용됩니다. startThread() 메소드가 모두 인 경우 RunnableThread이 GC 완료된 후에 만 ​​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가 할당된다. 그 익명 스레드의 스택, 맞습니까? 각 스레드는 자체 스택을 가지고 있지만 동일한 힙을 공유하기 때문입니다. 또한 내부 클래스 (익명 클래스) 외부 범위에있는 변수에 액세스 할 수있는 유일한 방법은 생각하기 때문에 스레드에 대한 올바른 변수를 선언하는 것입니다, 맞습니까? – peter

+0

예, var9는 새 스레드의 스택에 있습니다. var7과 동일합니다. 더 명확하게하기 위해 내 대답을 편집했습니다 @ user1389813. – Gray

+0

새 스레드가 시작되지 않으면 어떻게 될지 궁금합니다. – peter