[c#] .NET의 MemoryStream이 닫히지 않으면 메모리 누수가 발생합니까?

다음 코드가 있습니다.

MemoryStream foo(){
    MemoryStream ms = new MemoryStream();
    // write stuff to ms
    return ms;
}

void bar(){
    MemoryStream ms2 = foo();
    // do stuff with ms2
    return;
}

내가 할당 한 MemoryStream이 나중에 폐기되지 않을 가능성이 있습니까?

나는 이것을 수동으로 닫아야한다고 주장하는 피어 리뷰를 받았는데 그가 유효한 포인트가 있는지 여부를 알 수있는 정보를 찾을 수 없습니다.



답변

일회용품이라면 항상 폐기해야합니다. Disposed를 확인하기 위해 메서드에 using문을 사용해야합니다 .bar()ms2

결국 가비지 수집기에 의해 정리되지만 항상 Dispose를 호출하는 것이 좋습니다. 코드에서 FxCop을 실행하면 경고로 플래그가 지정됩니다.


답변

최소한 현재 구현에서는 아무것도 유출하지 않습니다.

Dispose를 호출하면 MemoryStream에서 사용하는 메모리가 더 빨리 정리되지 않습니다. 그것은 또는 당신에게 유용하지 않을 수도 있습니다 호출 후 읽기 / 쓰기 통화 가능한되는 것을 스트림을 중지합니다.

당신이 절대적으로 당신이하는 것이 있다면 결코 스트림의 다른 종류에 MemoryStream을에서 이동하지 않으려는, 당신에게 폐기를 호출하지 어떤 해를 할 수 없을거야. 그러나, 당신이 이제까지 경우 부분적으로 있기 때문에 일반적으로 좋은 연습이다 다른 스트림을 사용하는 변화를, 당신은 당신이 초기에 쉬운 방법을 선택하기 때문에 찾기 어려운 버그 물리지하지 않으려는. (반면에 YAGNI 논쟁이 있습니다 …)

어쨌든이를 수행하는 또 다른 이유는 새로운 구현 Dispose에서 해제되는 리소스를 도입 할 수 있다는 것입니다.


답변

예 거기 누출 은 누출을 정의하고 나중에 얼마나 큰 의미 방식에 따라 …

누수로 인해 “메모리가 할당 된 상태로 남아 있어도 사용할 수 없음”을 의미하고 후자의 경우 dispose를 호출 한 후 언제든지 사용할 수 있음을 의미하는 경우, 영구적 인 것은 아니지만 누수가있을 수 있습니다 (예 : 애플리케이션 런타임의 수명).

MemoryStream을에서 사용하는 관리되는 메모리를 확보하기 위해, 당신은 그것을 unreference 할 필요가 그래서 바로 가비지 컬렉션 대상이되고, 그것에 대한 참조를 무효로. 이 작업을 수행하지 않으면 사용을 마친 시점부터 참조가 범위를 벗어날 때까지 일시적인 누수가 발생합니다. 그 동안 메모리를 할당에 사용할 수 없기 때문입니다.

using 문 (단순히 dispose를 호출하는 것보다)의 이점은 using 문에서 참조를 선언 할 수 있다는 것입니다. using 문이 완료되면 dispose가 호출 될뿐만 아니라 참조가 범위를 벗어나서 참조를 효과적으로 무효화하고 “reference = null”코드를 작성하는 것을 기억할 필요없이 즉시 가비지 수집 대상 개체를 만듭니다.

무언가를 즉시 참조 해제하지 않는 것은 고전적인 “영구적 인”메모리 누수는 아니지만 확실히 동일한 효과를가집니다. 예를 들어, Dispose를 호출 한 후에도 MemoryStream에 대한 참조를 유지하고 메서드에서 조금 더 아래로 더 많은 메모리를 할당하려고하면 … 여전히 참조 된 메모리 스트림에서 사용중인 메모리를 사용할 수 없습니다. 참조를 무효화하거나 dispose를 호출하여 사용을 완료하더라도 범위를 벗어날 때까지


답변

전화 .Dispose()(또는로 래핑 Using)는 필요하지 않습니다.

전화 한 이유 .Dispose()가능한 한 빨리 자원해제하기 위해서 입니다.

예를 들어 제한된 메모리 세트와 수천 개의 요청이 들어오는 Stack Overflow 서버를 생각해보십시오. 예정된 가비지 수집을 기다리지 않고 최대한 빨리 메모리를 해제하여 사용할 수 있도록합니다. 새로운 수신 요청.


답변

이것은 이미 답변되어 있지만, 정보 은닉의 좋은 구식 원칙은 향후 언젠가 리팩토링을 원할 수 있음을 의미합니다.

MemoryStream foo()
{
    MemoryStream ms = new MemoryStream();
    // write stuff to ms    
    return ms;
}

에:

Stream foo()
{
   ...
}

이것은 호출자가 어떤 종류의 Stream이 반환되는지 신경 쓰지 않아야 함을 강조하고 내부 구현을 변경할 수있게합니다 (예 : 단위 테스트를 위해 모의 할 때).

바 구현에서 Dispose를 사용하지 않은 경우 문제가 발생해야합니다.

void bar()
{
    using (Stream s = foo())
    {
        // do stuff with s
        return;
    }
}


답변

모든 스트림은 IDisposable을 구현합니다. 메모리 스트림을 using 문으로 감싸면 멋지고 멋질 것입니다. using 블록은 스트림이 무엇이든 상관없이 닫히고 삭제되도록합니다.

Foo를 호출 할 때마다 (MemoryStream ms = foo ()) 사용할 수 있으며 여전히 괜찮을 것이라고 생각합니다.


답변

메모리 누수는 발생하지 않지만 코드 검토자가 스트림을 닫아야한다고 표시하는 것이 정확합니다. 그렇게하는 것이 예의입니다.

메모리 누수가 발생할 수있는 유일한 상황은 실수로 스트림에 대한 참조를 남겨두고 닫지 않는 경우입니다. 당신은 여전히 정말 메모리가 누수되지 않습니다,하지만 당신은 하는 당신이 그것을 사용하고 주장하는 것을 불필요하게 시간을 연장.