program tip

개체를 null 대 Dispose ()로 설정

radiobox 2020. 8. 9. 10:16
반응형

개체를 null 대 Dispose ()로 설정


저는 CLR과 GC가 작동하는 방식에 매료되었습니다 (C #, Jon Skeet의 서적 / 게시물 등을 통해 CLR을 읽고 이에 대한 지식을 확장하기 위해 노력하고 있습니다).

어쨌든, 말하는 것의 차이점은 무엇입니까?

MyClass myclass = new MyClass();
myclass = null;

또는 MyClass에서 IDisposable 및 소멸자를 구현하고 Dispose ()를 호출하여?

또한 using 문이있는 코드 블록 (예 : 아래)이있는 경우 코드를 단계별로 실행하고 using 블록을 종료하면 개체가 폐기됩니까? 아니면 가비지 수집이 발생합니까? 어쨌든 using 블록에서 Dispose ()를 호출하면 어떻게됩니까?

using (MyDisposableObj mydispobj = new MyDisposableObj())
{

}

스트림 클래스 (예 : BinaryWriter)에는 Finalize 메서드가 있습니까? 왜 그것을 사용하고 싶습니까?


폐기와 가비지 수집을 분리하는 것이 중요합니다. 그것들은 완전히 분리 된 것입니다. 한 가지 공통점은 제가 잠시 후에 다룰 것입니다.

Dispose, 가비지 수집 및 마무리

using을 작성할 때, Dispose본문의 코드 using가 예외를 throw 하더라도 호출 되는 try / finally 블록의 구문 설탕 일뿐 입니다. 없는 오브젝트가 블록의 끝에서 가비지 수집이 있음을 의미한다.

폐기는 관리되지 않는 리소스 (비 메모리 리소스)에 대한 것입니다. UI 핸들, 네트워크 연결, 파일 핸들 등이 될 수 있습니다. 이들은 제한된 리소스이므로 일반적으로 가능한 한 빨리 해제하는 것이 좋습니다. IDisposable유형이 관리되지 않는 리소스를 직접 (일반적으로를 통해 IntPtr) 또는 간접적으로 (예 : Stream, a SqlConnection등을 통해) "소유"할 때마다 구현해야합니다 .

가비지 수집 자체는 메모리에 관한 것입니다. 가비지 수집기는 더 이상 참조 할 수없는 개체를 찾아 해제 할 수 있습니다. 그래도 항상 가비지를 찾지는 않습니다. 필요한 것을 감지 할 때만 (예 : 힙의 한 "세대"가 메모리가 부족한 경우).

비틀기는 마무리 입니다. 가비지 수집기는 더 이상 도달 할 수 없지만 종료자가있는 개체 목록을 유지합니다 ( ~Foo()C # 에서처럼 다소 혼란 스럽지만 C ++ 소멸자와는 다릅니다). 메모리가 해제되기 전에 추가 정리를 수행해야하는 경우를 대비하여 이러한 개체에서 종료자를 실행합니다.

종료자는 해당 유형의 사용자가 규칙적인 방식으로 처리하는 것을 잊은 경우 리소스를 정리하는 데 거의 항상 사용됩니다. 그래서 당신은을 열면 FileStream하지만 전화하는 것을 잊지 Dispose또는 Close종료 자는 것, 결국 당신을위한 기본 파일 핸들을 해제. 잘 작성된 프로그램에서 파이널 라이저는 제 생각에는 거의 실행되지 않아야합니다.

변수 설정 null

변수 설정에 대한 한 가지 작은 점 null은 가비지 수집을 위해 거의 필요하지 않습니다. 내 경험상 객체의 "일부"가 더 이상 필요하지 않은 경우는 드물지만 멤버 변수 인 경우 가끔 수행 할 수 있습니다. 지역 변수 인 경우 JIT는 일반적으로 참조를 다시 사용하지 않을 때를 알 수있을만큼 충분히 똑똑합니다 (릴리스 모드에서). 예를 들면 :

StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();

// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);

// These aren't helping at all!
x = null;
sb = null;

// Assume that x and sb aren't used here

이 한 시간 에 지역 변수를 설정하는 가치는 null당신이 루프에있어, 루프의 필요성을 일부 가지 변수를 사용하는 경우입니다 그러나 당신은 당신이 안되는 지점에 도달했습니다 알고있다. 예를 들면 :

SomeObject foo = new SomeObject();

for (int i=0; i < 100000; i++)
{
    if (i == 5)
    {
        foo.DoSomething();
        // We're not going to need it again, but the JIT
        // wouldn't spot that
        foo = null;
    }
    else
    {
        // Some other code 
    }
}

IDisposable / finalizer 구현

So, should your own types implement finalizers? Almost certainly not. If you only indirectly hold unmanaged resources (e.g. you've got a FileStream as a member variable) then adding your own finalizer won't help: the stream will almost certainly be eligible for garbage collection when your object is, so you can just rely on FileStream having a finalizer (if necessary - it may refer to something else, etc). If you want to hold an unmanaged resource "nearly" directly, SafeHandle is your friend - it takes a bit of time to get going with, but it means you'll almost never need to write a finalizer again. You should usually only need a finalizer if you have a really direct handle on a resource (an IntPtr) and you should look to move to SafeHandle as soon as you can. (There are two links there - read both, ideally.)

Joe Duffy has a very long set of guidelines around finalizers and IDisposable (co-written with lots of smart folk) which are worth reading. It's worth being aware that if you seal your classes, it makes life a lot easier: the pattern of overriding Dispose to call a new virtual Dispose(bool) method etc is only relevant when your class is designed for inheritance.

This has been a bit of a ramble, but please ask for clarification where you'd like some :)


When you dispose an object, the resources are freed. When you assign null to a variable, you're just changing a reference.

myclass = null;

After you execute this, the object myclass was referring to still exists, and will continue to until the GC gets around to cleaning it up. If Dispose is explicitly called, or it's in a using block, any resources will be freed as soon as possible.


The two operations don't have much to do with each others. When you set a reference to null, it simply does that. It doesn't in itself affect the class that was referenced at all. Your variable simply no longer points to the object it used to, but the object itself is unchanged.

When you call Dispose(), it's a method call on the object itself. Whatever the Dispose method does, is now done on the object. But this doesn't affect your reference to the object.

The only area of overlap is that when there are no more references to an object, it will eventually get garbage collected. And if the class implements the IDisposable interface, then Dispose() will be called on the object before it gets garbage collected.

But that won't happen immediately after you set your reference to null, for two reasons. First, other references may exist, so it won't get garbage collected at all yet, and second, even if that was the last reference, so it is now ready to be garbage collected, nothing will happen until the garbage collector decides to delete the object.

Calling Dispose() on an object doesn't "kill" the object in any way. It is commonly used to clean up so that the object can be safely deleted afterwards, but ultimately, there is nothing magical about Dispose, it's just a class method.

참고URL : https://stackoverflow.com/questions/574019/setting-an-object-to-null-vs-dispose

반응형