2008-10-28 4 views
3

이 코드 블록

public void ManageInstalledComponentsUpdate() 
     { 
      IUpdateView view = new UpdaterForm(); 
      BackgroundWorker worker = new BackgroundWorker(); 
      Update update = new Update(); 
      worker.WorkerReportsProgress = true; 
      worker.WorkerSupportsCancellation = true; 
      worker.DoWork += new DoWorkEventHandler(update.DoUpdate); 
      worker.ProgressChanged += new ProgressChangedEventHandler(view.ProgressCallback); 
      worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(view.CompletionCallback);    
      worker.RunWorkerAsync(); 
      Application.Run(view as UpdaterForm);  
     } 

그것은 모두가 잘 작동을 고려하지만 객체 (노동자,보기 및 업데이트) 쓰레기 수집되지 않는 이유를 이해 할

+0

어떻게 수집되지 않는지 알고 계십니까? – StingyJack

답변

7

스레드 수는 루트 개체로 계산됩니다. BackgroundWorker가 어떻게 작동하는지 정확히 알지 못하지만 기본 스레드 메서드가 worker 인스턴스의 상태에 액세스 할 가능성이 높습니다. 따라서 작업 스레드 자체는 적어도 스레드가 종료 될 때까지 BackgroundWorker 인스턴스를 활성 상태로 유지합니다.

물론입니다. 컬렉션은 또한 다른 모든 (실제) 객체가 작업자 객체를 참조 해제해야한다고 요구합니다. 스택 변수의 콜렉션은 디버그/릴리즈에서 다를 수 있으며 디버거가 첨부되어 있거나 없을 수도 있습니다.

[편집] 또한 언급했듯이; (코드에서) 작업자의 이벤트 핸들러는 대리자를 통해 "보기"및 "업데이트"개체를 유지하지만 그 반대의 경우는 유지하지 않습니다. 근로자가 "보기"및 "업데이트"보다 수명이 짧으면 이벤트 구독을 취소하는 것에 대해 편집증을받을 필요가 없습니다. 작업자가 유일하게 참조하는 "SomeTarget"개체를 포함하도록 코드를 편집했습니다.이 효과 (예 : 대상이 작업자와 함께 사망 함)가 표시되어야합니다.

스레드가 죽으면 다시 작업자가 수집됩니다. 여기에 증거가 있습니다. 작업자가 종료보고 후 "완료 노동자"를 참조한다 : 당신이 노동자에 연결된 이벤트 처리기가 될 때까지, 그래서

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 
class Demo : Form 
{ 
    class ChattyWorker : BackgroundWorker 
    { 
     ~ChattyWorker() 
     { 
      Console.WriteLine("Worker finalized"); 
     } 
    } 
    class SomeTarget 
    { 
     ~SomeTarget() 
     { 
      Console.WriteLine("Target finalized"); 
     } 
     public SomeTarget() 
     { 
      Console.WriteLine("Target created"); 
     } 
     public void Foo(object sender, EventArgs args) 
     { 
      Console.WriteLine("Foo"); 
     } 
    } 
    static void Collect(object sender, EventArgs args) 
    { 
     Console.WriteLine("Collecting..."); 
     GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    } 
    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); 
     timer.Interval = 100; 
     timer.Tick += Collect; 
     timer.Start(); 

     ChattyWorker worker = new ChattyWorker(); 
     worker.RunWorkerCompleted += new SomeTarget().Foo; 
     worker.DoWork += delegate 
     { 
      Console.WriteLine("Worker starting"); 
      for (int i = 0; i < 10; i++) 
      { 
       Thread.Sleep(250); 
       Console.WriteLine(i); 
      } 
      Console.WriteLine("Worker exiting"); 
     }; 
     worker.RunWorkerAsync(); 
    } 
    [STAThread] 
    static void Main() 
    { // using a form to force a sync context 
     Application.Run(new Demo()); 
    } 
} 
+0

나는 그것이 왜 투표에 부쳐 졌는지 알고 싶다 ... –

0

이벤트 핸들러, 참조입니다을, 그것은 "도달"으로 간주되지 않을 것이다.

ComplitionCallback에서 이벤트 처리기를 언 Hook 처리합니다.

+0

대의원은 일방적 인 언급이다; BackgroundWorker의 이벤트는 "보기"및 "업데이트"개체를 유지하지만 그 반대의 방식은 유지하지 않습니다. 즉 작업자가 범위를 벗어날 경우 핸들러를 푸는 데 엄청난 이익이 없습니다. 기분이 자유 롭다. –

-1

해당 지역 변수 객체는 함수가 종료 될 때까지 즉, 양식이 종료 될 때까지 유지됩니다. 따라서 Run을 호출하기 전에 이들을 null로 설정하거나 다른 컨텍스트로 이동하십시오.

public void ManageInstalledComponentsUpdate() { 
    UpdaterForm form = new UpdaterForm(); 
    FireAndForgetWorker(form); 
    Application.Run(form); //does not return until form exits 
} 

void FireAndForgetWorker(IUpdateView view) { 
    BackgroundWorker worker = new BackgroundWorker(); 
    Update update = new Update(); 
    worker.WorkerReportsProgress = true; 
    worker.WorkerSupportsCancellation = true; 
    worker.DoWork += new DoWorkEventHandler(update.DoUpdate); 
    worker.ProgressChanged += new ProgressChangedEventHandler(view.ProgressCallback); 
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(view.CompletionCallback); 
    worker.RunWorkerAsync(); 
} 

주의 사항

는 vsick합니다 :

다음 프로그램을 실행 해보십시오, 당신은 놀라게 될 것입니다 x는 영원히 살아있다.

using System;

class FailsOnGarbageCollection 
{ ~FailsOnGarbageCollection() { throw new NotSupportedException(); } } 

class Program{ 
    static void WaitForever() { while (true) { var o = new object(); } } 

    static void Main(string[] args) 
    { 
     var x = new FailsOnGarbageCollection(); 
     //x = null; //use this line to release x and cause the above exception 
     WaitForever(); 
    } 
} 
+0

그건 맞지 않아. 지역 변수는 나머지 함수 ('this'를 포함하여!)에서 사용되지 않을 때 살아남지 못합니다. – svick

+0

죄송합니다.하지만 괜찮습니다. 위의 프로그램을 사용하여 변수를 null로 지정해야하는 이유를 확인하십시오. – jyoung

+0

* 릴리스 모드 *에서 프로그램을 사용해보십시오. ** 변수를 null로 설정하지 않아도됩니다. (이 경우 적어도 필드에 적합 할 수 있습니다.) – svick