2011-02-09 7 views
0

예를 들어 은 가비지 수집중인 타이머를 방지하기 위해 여기에서 수행하는 것처럼 타이머 인스턴스를 목록에 추가해야합니까? 사실 콜백이 익명이 아닌 경우 aswer는 yes입니다. 익명이므로 익명 메소드 블록에서 액세스 할 수있는 메소드 블록의 변수는 익명 메소드가 완료 될 때만 가비지 수집됩니다. 내가 뭐하는 거지 같은 경우에는 필요가 심판을 저장 없습니다 .. :익명 메소드에서 액세스 할 수있는 메소드 변수는 언제 가비지 수집됩니까?

private static List<Timer> timers = new List<Timer>(); 

public static void RunCallbackAfter(Action callback, int secondsToWait) 
{ 
     Timer t = null; 
     t = new Timer(new TimerCallback(delegate(object state) 
      { 
       SomeThread.BeginInvoke(callback); 
       timers.Remove(t); 
      }), null, secondsToWait*1000, Timeout.Infinite); 
     timers.Add(t); 
} 

답변

2

익명 메서드로 캡처 된 변수가 참조하는 개체는 익명 메서드로 만든 대리자가 가비지 수집 대상이 될 때까지 가비지 수집 대상이되지 않습니다. 그러나

, 그것은 단지의 대리자에 대한 참조를 가지고 Timer, 그리고 다른 아무것도 나는이 가정 모두 가비지 컬렉션의 대상이 될 것입니다 생각, 타이머에 대한 참조가없는 경우는 실제로 타이머의 종류 참조를 유지해야합니다. (좀 타이머 이를 필요로 할 것을 기억하는 것, 일부 을하지 않습니다. 내가하는 어떤 기억이 안나요.)

또한, 당신은 다음을 익명 메소드 내에서 timers.Remove(t) 전화를 제거한 경우 처음에는 t을 캡처하지 않을 것입니다. 단지 캡쳐 된 변수는 수명이 길지 않습니다 ... 모든 변수는 익명 메소드를 포함하고 있습니다.

0

번호 당신은 당신의 타이머를 멀리 숨길 필요가 없습니다. 일반적으로 대리인이 참조하기 때문에 가비지 수집됩니다. 그러나 Timer 생성자는 기본 런타임과 함께 참조를 배치하므로 정상적으로 수행되어야합니다.

에릭 Lippert의 아마 자신의 블로그 게시물에 할 말이있다 : The implementation of anonymous methods in C# and its consequences (part 1)

귀하의 Timer 변수 t 익명 메서드에 대한 참조가있는 한만큼 접근 할 수있을 것입니다. 익명의 방법은 이벤트가 해지 될 때까지 계속 참조됩니다. 적어도 그렇게 오래.

에릭 리 퍼트 (Eric Lippert)에 따르면 C# 컴파일러는 메서드의 컨텍스트 (포함하는 개체의 this 포함)를 모두 작은 컴파일러에서 생성 된 클래스로 묶은 코드를 다른 것으로 변환합니다. 그래서 익명의 메서드 (또는 대리자) 자체가 타이머에 대한 참조를 포함하고있는 것처럼 보입니다.

아, 그리고이 스레드의 다른 모든 사람들은 정확합니다. 나는 방금 일부 물건을 훑어 보았고 (C# 컴파일러가 익명 ​​메소드를 동시에 처리하는 방법을 배웠습니다).

예, 순환 참조가 있습니다. 하지만 타이머를 만들면 런타임/윈도우의 어딘가에 연결해야합니다. 수표를 가지고 가자.

리플렉터를 사용하면 System.Timer.Timer()에서 TimerBase까지 트레일을 따라갈 수 있습니다. 외부 신호는 AddTimerNative입니다. 나는 그걸 들여다 보지 못 하겠지만 타이머를 OS에 등록 할 것입니다.

결론 : 타이머는 범위에서 벗어나지 않습니다. 타이머는 작동 할 때까지 OS에서 참조하므로 범위를 벗어나지 않습니다.

+0

huh? – markmnl

+0

아를 도와주세요 .. _closure_는 익명 메소드 – markmnl

+1

에서 액세스 할 수있는 변수의 이름입니다. 그러나 콜백과 타이머는 순환 참조를 형성합니다. 콜백에 대한 외부 참조가 있다면 아무 문제가 없을 것입니다 (단, 클로저에 있는지 확인하기 위해 외부 변수를 만져야한다는 점만 제외하고는) ... – bdonlan

0

일반적으로 C#의 익명 함수는 anon 함수 자체가 소멸 될 때까지을 참조하는 모든 로컬 변수 을 유지합니다. 물론이 경우 remove 호출을 제거하면 참조가 제거되므로 더 이상 변수가 콜백에 의해 활성 상태로 유지되지 않습니다.

그러나 여기서는 순환 참조를 형성합니다. 외부 참조가 없으면 타이머와 콜백이 동시에 파괴 될 수 있습니다. 타이머를 시작하면 C#에서 살아있는 외부 참조로 카운트, 그래서 당신의 질문에 완전히 대답 할 수없는 경우 확실하지 않다. 시작된 타이머가 외부 참조를 갖는 것으로 처리되면 타이머와 콜백이 모두 유지됩니다.

관련 문제