업데이트 : 나는 여기 에서 찾을 수있는 기사의 기초로이 질문을 사용했다 ; 이 문제에 대한 추가 논의는 그것을 참조하십시오. 좋은 질문에 감사드립니다!
Schabse의 답변 은 물론 정확하고 질문에 대한 답변 이지만 질문하지 않은 중요한 변형이 있습니다.
하면 어떻게됩니까 font4 = new Font()
발생 후 관리되지 않는 리소스가 생성자가 아니라 할당 된 전 에서의 ctor 반환 및 채우기 font4
기준으로?
좀 더 명확히하겠습니다. 다음이 있다고 가정합니다.
public sealed class Foo : IDisposable
{
private int handle = 0;
private bool disposed = false;
public Foo()
{
Blah1();
int x = AllocateResource();
Blah2();
this.handle = x;
Blah3();
}
~Foo()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (this.handle != 0)
DeallocateResource(this.handle);
this.handle = 0;
this.disposed = true;
}
}
}
이제 우리는
using(Foo foo = new Foo())
Whatever(foo);
이것은
{
Foo foo = new Foo();
try
{
Whatever(foo);
}
finally
{
IDisposable d = foo as IDisposable;
if (d != null)
d.Dispose();
}
}
확인. Whatever
던진다 고 가정하자 . 그런 다음 finally
블록이 실행되고 리소스가 할당 해제됩니다. 문제 없어요.
Blah1()
던진다 고 가정하자 . 그런 다음 리소스가 할당되기 전에 throw가 발생합니다. 객체가 할당되었지만 ctor는 반환 foo
되지 않으므로 채워 try
지지 않습니다 finally
. 개체 참조가 분리되었습니다. 결국 GC는이를 발견하여 종료 자 대기열에 넣습니다. handle
여전히 0이므로 종료자는 아무 작업도 수행하지 않습니다. 종료자는 생성자가 완료되지 않은 객체가 종료되는 상황에서 견고해야합니다 . 당신은있다 필요한 이 강한 파이널 라이저를 작성. 이것이 최종 결정자를 전문가에게 맡기고 직접 시도하지 않아야하는 또 다른 이유입니다.
Blah3()
던진다 고 가정하자 . 리소스가 할당 된 후에 throw가 발생합니다. 그러나 다시, foo
채워지지 않고, 우리는 절대로 입력하지 않으며 finally
, 객체는 종료 자 스레드에 의해 정리됩니다. 이번에는 핸들이 0이 아니므로 종료자가이를 정리합니다. 다시 말하지만, 종료자는 생성자가 성공한 적이없는 객체에서 실행되지만 종료자는 어쨌든 실행됩니다. 이번에는해야 할 일이 있었기 때문에 분명히해야합니다.
이제 던졌다 고 가정 Blah2()
합니다. 던지는 리소스가 할당 된 후, 채워 지기 전에 발생합니다 handle
! 다시 말하지만, 파이널 라이저는 실행되지만 지금 handle
은 여전히 0이고 핸들을 누출합니다!
이 누출이 발생하지 않도록하려면 매우 영리한 코드 를 작성해야합니다 . 자, 당신의 Font
자원 의 경우 도대체 누가 신경 쓰나요? 글꼴 핸들이 누출됩니다. 그러나 예외의시기에 관계없이 관리되지 않는 모든 리소스를 정리 하도록 절대적으로 요구 하는 경우 매우 어려운 문제가 발생합니다.
CLR은 잠금으로이 문제를 해결해야합니다. C # 4 이후 lock
문 을 사용하는 잠금은 다음과 같이 구현되었습니다.
bool lockEntered = false;
object lockObject = whatever;
try
{
Monitor.Enter(lockObject, ref lockEntered);
lock body here
}
finally
{
if (lockEntered) Monitor.Exit(lockObject);
}
Enter
매우 신중하게 그렇게 기록 된 예외가 던져 상관없이가 , lockEntered
true로 설정 하고있는 경우에만 경우 잠금이 실제로 촬영했다. 비슷한 요구 사항이 있다면 실제로 작성해야 할 것은 다음과 같습니다.
public Foo()
{
Blah1();
AllocateResource(ref handle);
Blah2();
Blah3();
}
그리고 내부 에서 무슨 일이 일어나더라도 할당을 해제해야 할 때만 채워지 도록 AllocateResource
똑똑하게 작성하십시오 .Monitor.Enter
AllocateResource
handle
그렇게하는 기술을 설명하는 것은이 답변의 범위를 벗어납니다. 이 요구 사항이 있으면 전문가에게 문의하십시오.