GC.Collect () 후에 종료자가 호출되지 않음 [중복]
나는 근본적인 것을 놓치고 있다고 생각하며 당신이 도울 수 있기를 바랍니다. 아래 코드는 개체를 만들고 참조를 제거하며 가비지 수집기를 호출합니다. 내 기대는 Readline에 서있을 때 SomeClass의 종료자가 호출된다는 것입니다. 그렇지 않습니다. 루프에서 GC.Collect를 호출하여 종료 자 스레드가 시작되도록 Sleep () 호출을 추가해 보았습니다. 발생하지 않습니다.
메인이 끝날 때만 파이널 라이저가 맞았지만 놀랍게도 두 번 맞았습니다. 내가 무엇을 놓치고 있습니까?
class Program
{
public static void Main(string[] args)
{
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
Console.ReadLine();
}
}
class SomeClass
{
string ss;
public SomeClass(string s) { ss = s; }
~SomeClass()
{
var hash = this.GetHashCode();
}
}
부록 디버그 모드와 릴리스 모드에서 프로그램을 실행하는 데는 차이가 있습니다. 아래 프로그램은 디버그 모드에서 생성하는 Start - Done - Finalize
반면 릴리스 모드에서는 로그 파일에 Start - Finalize - Done
. 후자는 내가 기대했던 것입니다.
class Program
{
private static string logfile = @"c:\temp\log.txt";
public static void Main(string[] args)
{
File.WriteAllText(logfile, "Start\n");
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
File.AppendAllText(logfile, "Done\n");
}
}
class SomeClass
{
private static string logfile = @"c:\temp\log.txt";
public string SomeString { get; set; }
public SomeClass(string s) { SomeString = s; }
~SomeClass()
{
File.AppendAllText(logfile, "Finalize\n");
}
}
답변
가비지 수집 된 개체는 마무리에 적합하고 마무리 대기열에 놓입니다. 이러한 종료자가 실행될 것이라는 보장은 전혀 없습니다 .
"당신이 아는 모든 것이 잘못되었을 때" 라고 적절하게 불리는 Eric Lippert의 훌륭한 포스트로 여러분을 리디렉션 할 것입니다. 특히:
통념 : 변수를 null로 설정하면 이전에 변수에서 참조한 개체에서 종료자가 실행됩니다. 변수를 null로 설정해도 변수 값을 변경하는 것 외에는 아무 일도 발생하지 않습니다. 변수가 해당 개체에 대한 마지막 살아있는 참조 인 경우 가비지 수집기가 개체가 속한 세대에 관계없이 수집기를 실행할 때 해당 사실이 발견됩니다. GC가 실행됩니다.)
그리고 심지어 GC.Collect()
:
통념 : 호출
GC.Collect()
하면 종료자가 실행됩니다. 아니요, 수집이 발생합니다. 이는 종료 후보 인 개체를 식별 할 수 있지만 종료 자 스레드를 강제로 예약하지는 않습니다. 그것이 당신이 원하는 것이라면-테스트 목적으로 만 제발! — 그런 다음GC.WaitForPendingFinalizers()
.
따라서 성공의 가장 좋은 기회는 GC.WaitForPendingFinalizers()
. 그러나 그럼에도 불구하고 나머지 게시물 ( 및 그 속편 )을 참조하면 FINALIZERS는 실행이 보장되지 않습니다 . 그것에 의존하지 마십시오.
이 질문 에 대한 자세한 설명을 작성하여 추가 연구의 시작점으로 사용할 수 있습니다.