2009-05-29 3 views
9

다음과 같은 생성자에서 예외를 throw 할 때 메모리 누수가 있습니까?.NET의 생성자에서 예외를 throw하는 중

class Victim 
{ 
    public string var1 = "asldslkjdlsakjdlksajdlksadlksajdlj"; 

    public Victim() 
    { 
     //throw new Exception("oops!"); 
    } 
} 

가비지 수집기가 실패한 개체를 수집합니까?

+0

간신히 관련,하지만 유용한 팁 : 컨트롤의 생성자에서 발생한 예외에 대한주의하십시오. 디자이너가 컨트롤/폼을 무너 뜨릴 수 있습니다. Initialize() 메서드를 사용하고 그 메서드를 외부에서 호출하여 반올림합니다 (그러나이 메서드는 마음에 들지 않습니다). –

답변

23

일반적으로 이것은 메모리가 누출되지 않는 관점에서 안전합니다. 그러나 유형에서 관리되지 않는 리소스를 할당하는 경우 생성자에서 예외를 throw하는 것은 위험합니다. 다음 예제를 사용하십시오

public class Foo : IDisposable { 
    private IntPtr m_ptr; 
    public Foo() { 
    m_ptr = Marshal.AllocHGlobal(42); 
    throw new Exception(); 
    } 
    // Most of Idisposable implementation ommitted for brevity 
    public void Dispose() { 
    Marshal.FreeHGlobal(m_ptr); 
    } 
} 

이 클래스는 사용하는 블록을 사용하더라도 만들려고 할 때마다 메모리가 누출됩니다. 예를 들어,이 누수 메모리. 재미

using (var f = new Foo()) { 
    // Won't execute and Foo.Dispose is not called 
} 
+0

using 문이 실제로 실행되지 않을뿐만 아니라 .Dispose()를 호출하기 위해 만들어진 인스턴스가 없으므로 Foo의 .Dispose() 메서드가 호출되지 않는다는 점을 분명히해야합니다. – jrista

+0

@jrista 업데이트 됨 – JaredPar

+0

난 여기에 파티에 심각하게 늦었지만, 시도하지 않았다면 생성자가 문제없이이 문제를 해결할 수 있을까요? – Gusdor

2

예, 가비지 수집기는 개체에 이미 할당 된 관리되는 리소스를 회수합니다. 관리되지 않는 리소스를 초기화 한 경우 정상적인 방법으로 리소스를 정리해야합니다.

1

예외가 발생하기 전에 획득 한 다른 리소스에 따라 다릅니다. 나는 생성자에서 예외를 던지는 것은 훌륭하다고 생각하지 않지만 finalizer에서 던지거나 폐기하는 것은 훨씬 더 나쁘다.

+2

"파이널 라이저에서 던지거나 처분하는 것이 훨씬 더 낫습니다." Dispose를 던져도 괜찮습니다. 예를 들어 FileStream은 스트림을 플러시 할 수없는 경우 (예 : 네트워크 오류로 인해) throw됩니다. 가능하다면 던지기를 피하고,해야한다면 그렇게하십시오. FileStream의 경우 예외를 삼키는 것은 호출자에게 파일이 성공적으로 기록되었다는 인상을 주므로 throw하는 것보다 훨씬 위험합니다. – Joe

4

, 난 그냥 어제 similar question에 도움이 때문이다.

파생 형식이있는 경우 파생 형식의 일부가 초기화되지만 다른 부분은 초기화되지 않으므로 더 큰 문제입니다. 메모리 관점에서는 가비지 컬렉터가 무엇이 어디 있는지 알고 있기 때문에 별 문제가되지 않습니다. 그러나 관리되지 않는 리소스 (IDisposable 구현)가있는 경우 문제가 발생할 수 있습니다.

9

관리되지 않는 리소스를 만들지 않은 경우에는 생성자에서 예외를 throw하는 것이 좋습니다. 그러나 생성자에서 관리되지 않는 리소스를 만드는 경우 throws를 포함하여 해당 생성자의 전체 본문을 try/catch로 래핑해야합니다. JaredPar의 좋은 예를 훔치는 :

public class Foo : IDisposable { 
    private IntPtr m_ptr; 
    public Foo() { 
    try 
    { 
     m_ptr = Marshal.AllocHGlobal(42); 
     throw new Exception(); 
    } 
    catch 
    { 
     Dispose(); 
     throw; 
    } 
    } 
    // Most of Idisposable implementation ommitted for brevity 
    public void Dispose() { 
    Marshal.FreeHGlobal(m_ptr); 
    } 
} 

다음은 지금 작동합니다 :

using (var f = new Foo()) { 
    // Won't execute, but Foo still cleans itself up 
} 
관련 문제