객체를 폐기하고 null로 설정해야합니까?


310

객체를 폐기하고 null로 설정해야합니까, 아니면 가비지 수집기가 객체가 범위를 벗어날 때 정리합니까?


4
객체를 null로 설정할 필요는 없지만 Dispose ()를 수행해야한다는 합의가있는 것 같습니다.
CJ7

3
: 제프 말했듯이 codinghorror.com/blog/2009/01/...
tanathos

9
객체가 IDisposable을 구현하면 항상 조언을 폐기합니다. 매번 사용 블록을 사용하십시오. 가정하지 말고 우연히 두지 마십시오. 그래도 물건을 null로 설정할 필요는 없습니다. 개체가 범위를 벗어났습니다.
피터

11
@peter : WCF 클라이언트 프록시에 "사용"블록을 사용하지 마십시오. msdn.microsoft.com/en-us/library/aa355056.aspx
nlawalker

9
그러나Dispose() 메소드 내에서 일부 참조를 null로 설정할 수 있습니다 ! 이것은이 질문에 대한 미묘한 변형이지만, 배치중인 객체가 "범위를 벗어난"것인지 알 수 없기 때문에 중요합니다 (호출 Dispose()이 보장되지는 않음). 추가 정보 : stackoverflow.com/questions/6757048/…
Kevin P. Rice

답변:


239

더 이상 사용되지 않거나 가비지 수집기가 적합 할 때 개체가 정리됩니다. 때로는 null범위를 벗어나기 위해 객체를 설정해야 할 수도 있지만 (예 : 더 이상 필요없는 정적 필드) 일반적으로로 설정할 필요가 없습니다 null.

객체 폐기와 관련하여 @Andre에 동의합니다. 객체 인 경우 IDisposable는이다 그것을 처리 할 수있는 좋은 아이디어 가 더 이상 객체가 관리되지 않는 리소스를 사용하는 경우 특히 필요없는 경우는. 관리되지 않는 리소스를 폐기하지 않으면 메모리 누수가 발생 합니다.

using프로그램이 using명령문 범위를 벗어나 면 명령문을 사용하여 오브젝트를 자동으로 폐기 할 수 있습니다 .

using (MyIDisposableObject obj = new MyIDisposableObject())
{
    // use the object here
} // the object is disposed here

기능적으로 다음과 같습니다.

MyIDisposableObject obj;
try
{
    obj = new MyIDisposableObject();
}
finally
{
    if (obj != null)
    {
        ((IDisposable)obj).Dispose();
    }
}

4
obj가 참조 유형 인 경우 finally 블록은 다음과 같습니다.if (obj != null) ((IDisposable)obj).Dispose();
Randy는 Monica

1
@Tuzo : 감사합니다! 그것을 반영하기 위해 편집했습니다.
Zach Johnson

2
에 관한 한 가지 언급 IDisposable. 객체 폐기 실패 일반적으로 잘 설계된 클래스에서 메모리 누수가 발생하지 않습니다 . C #에서 관리되지 않는 리소스로 작업 할 때는 아직 관리되지 않는 리소스를 해제하는 종료자가 있어야합니다. 즉, 자원을 수행해야 할 때 자원을 할당 해제하는 대신 가비지 콜렉터가 관리 대상 오브젝트를 완료 할 때 자원이 지연됩니다. 그래도 릴리스되지 않은 잠금과 같은 다른 많은 문제가 발생할 수 있습니다. IDisposable그래도 폐기해야합니다 !
Aidiakapi

@RandyLevy 당신은 그것에 대한 참조가 있습니까? 감사합니다
기본

그러나 내 질문은 Dispose ()가 논리를 구현해야한다는 것입니다. 뭔가해야합니까? 또는 내부적으로 Dispose ()가 GC 신호라고 할 때 좋은 신호입니까? 예를 들어 TextWriter의 소스 코드를 확인했으며 Dispose에는 구현이 없습니다.
Mihail Georgescu

137

C ++에서와 마찬가지로 개체는 C #에서 범위를 벗어나지 않습니다. 더 이상 사용하지 않으면 가비지 콜렉터가 자동으로 처리합니다. 이것은 변수의 범위가 완전히 결정적인 C ++보다 더 복잡한 접근법입니다. CLR 가비지 콜렉터는 작성된 모든 오브젝트를 적극적으로 통과하며 사용중인 경우이를 해결합니다.

객체는 한 함수에서 "범위를 벗어난"상태가 될 수 있지만 값이 반환되면 GC는 호출 함수가 반환 값을 유지하는지 여부를 확인합니다.

null가비지 수집은 다른 객체가 참조하는 객체를 계산하여 가비지 수집이 작동하므로 객체 참조를 설정 하지 않아도됩니다.

실제로, 당신은 파괴에 대해 걱정할 필요가 없습니다, 그것은 효과가 있으며 훌륭합니다 :)

DisposeIDisposable작업을 마쳤을 때 구현하는 모든 개체에 대해 호출해야 합니다. 일반적으로 다음 using과 같은 객체에 블록을 사용합니다 .

using (var ms = new MemoryStream()) {
  //...
}

편집 변수 범위에서. Craig는 변수 범위가 객체 수명에 어떤 영향을 미치는지 물었습니다. CLR의 이러한 측면을 올바르게 설명하려면 C ++ 및 C #의 몇 가지 개념을 설명해야합니다.

실제 변수 범위

두 언어 모두 변수는 클래스, 함수 또는 중괄호로 묶인 명령문 블록과 같이 정의 된 것과 동일한 범위에서만 사용할 수 있습니다. 그러나 미묘한 차이점은 C #에서는 중첩 블록에서 변수를 다시 정의 할 수 없다는 것입니다.

C ++에서 이것은 완벽하게 합법적입니다.

int iVal = 8;
//iVal == 8
if (iVal == 8){
    int iVal = 5;
    //iVal == 5
}
//iVal == 8

그러나 C #에서는 컴파일러 오류가 발생합니다.

int iVal = 8;
if(iVal == 8) {
    int iVal = 5; //error CS0136: A local variable named 'iVal' cannot be declared in this scope because it would give a different meaning to 'iVal', which is already used in a 'parent or current' scope to denote something else
}

생성 된 MSIL을 보면 함수에 사용되는 모든 변수가 함수 시작시 정의됩니다. 이 기능을 살펴보십시오.

public static void Scope() {
    int iVal = 8;
    if(iVal == 8) {
        int iVal2 = 5;
    }
}

아래는 생성 된 IL입니다. if 블록 내에 정의 된 iVal2는 실제로 함수 레벨에서 정의됩니다. 실제로 이것은 C #에 가변 수명에 관한 한 클래스 및 함수 수준 범위 만 있음을 의미합니다.

.method public hidebysig static void  Scope() cil managed
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init ([0] int32 iVal,
           [1] int32 iVal2,
           [2] bool CS$4$0000)

//Function IL - omitted
} // end of method Test2::Scope

C ++ 범위 및 객체 수명

스택에 할당 된 C ++ 변수는 범위를 벗어날 때마다 소멸됩니다. C ++에서는 스택이나 힙에 객체를 만들 수 있습니다. 스택에서 생성하면 실행이 범위를 벗어나면 스택에서 튀어 나와 파괴됩니다.

if (true) {
  MyClass stackObj; //created on the stack
  MyClass heapObj = new MyClass(); //created on the heap
  obj.doSomething();
} //<-- stackObj is destroyed
//heapObj still lives

C ++ 오브젝트가 힙에 작성되면 명시 적으로 파기해야합니다. 그렇지 않으면 메모리 누수입니다. 스택 변수에 대해서는 그런 문제가 없습니다.

C # 개체 수명

CLR에서 객체 (예 : 참조 유형)는 항상 관리되는 힙에 생성됩니다. 이것은 객체 생성 구문에 의해 더욱 강화됩니다. 이 코드 스 니펫을 고려하십시오.

MyClass stackObj;

C ++에서는 MyClass스택에 인스턴스를 만들고 기본 생성자를 호출합니다. C #에서는 MyClass아무것도 가리 키지 않는 클래스에 대한 참조를 만듭니다 . 클래스의 인스턴스를 만드는 유일한 방법은 new연산자 를 사용하는 것 입니다.

MyClass stackObj = new MyClass();

어떤 식 으로든 C # 객체는 newC ++에서 구문을 사용하여 생성 된 객체와 매우 유사합니다. 이들은 힙에서 생성되지만 C ++ 객체와 달리 런타임에 의해 관리되므로 파괴에 대해 걱정할 필요가 없습니다.

객체가 항상 힙에 있기 때문에 객체 참조 (예 : 포인터)가 범위를 벗어난다는 사실이 무질서하게됩니다. 단순히 객체에 대한 참조가 존재하는 것보다 객체를 수집할지 여부를 결정하는 데 더 많은 요소가 있습니다.

C # 개체 참조

Jon Skeet 은 Java의 객체 참조를 풍선에 연결된 문자열 조각 ( 객체)과 비교했습니다 . C # 객체 참조에도 동일한 비유가 적용됩니다. 단순히 객체를 포함하는 힙의 위치를 ​​가리 킵니다. 따라서 null로 설정하면 객체 수명에 즉각적인 영향을 미치지 않으며 풍선이 GC가 "팝핑"할 때까지 계속 존재합니다.

풍선 비유를 계속하면 풍선에 부착 된 끈이 ​​없으면 파괴 될 수 있다는 것이 논리적으로 보입니다. 실제로 이것은 참조 계산 된 개체가 관리되지 않는 언어에서 작동하는 방식과 정확히 동일합니다. 이 방법을 제외하고 순환 참조에는 잘 작동하지 않습니다. 두 개의 풍선이 끈으로 연결되어 있지만 풍선에 다른 끈이 없습니다. 간단한 심판 계산 규칙에 따라 전체 풍선 그룹이 "분리 된"경우에도 둘 다 계속 존재합니다.

.NET 객체는 지붕 아래의 헬륨 풍선과 매우 유사합니다. 지붕이 열리면 (GC가 실행 됨) 서로 묶여있는 풍선 그룹이있을 수 있지만 사용하지 않는 풍선이 뜹니다.

.NET GC는 세대 별 GC와 마크 앤 스윕의 조합을 사용합니다. 세대 별 접근 방식은 가장 최근에 할당 된 객체를 검사하는 것을 선호하는 런타임과 관련이 있습니다. 사용하지 않을 가능성이 높고 마크 및 스윕은 런타임에 전체 객체 그래프를 살펴보고 사용하지 않는 객체 그룹이있는 경우 작동합니다. 이것은 순환 종속성 문제를 적절하게 처리합니다.

또한 .NET GC는 다른 스레드 (파이널 라이저 스레드라고도 함)에서 실행되며 꽤 많은 작업을 수행하므로 기본 스레드에서 수행하면 프로그램이 중단됩니다.


1
@ Igor : '범위를 벗어남'이라는 것은 객체 참조가 컨텍스트를 벗어 났으며 현재 범위에서 참조 할 수 없음을 의미합니다. 분명히 이것은 여전히 ​​C #에서 발생합니다.
CJ7

@Craig Johnston은 컴파일러가 사용하는 변수 범위를 런타임에 의해 결정되는 변수 수명과 혼동하지 마십시오. 로컬 변수는 여전히 범위 내에 있지만 "라이브"되지 않을 수 있습니다.
Randy는 Monica

1
@Craig Johnston : blogs.msdn.com/b/ericgu/archive/2004/07/23/192842.aspx 참조 : "지역 변수가 범위가 끝날 때까지 범위가 끝날 때까지 계속 유지된다는 보장은 없습니다 런타임은 자신이 가지고있는 코드를 자유롭게 분석하고 특정 시점 이후의 변수 사용이 더 이상 없는지 판별하여 해당 시점 이후의 변수를 유지하지 않습니다 (즉, 목적으로 루트로 취급하지 않음) ")
Randy는 Monica

1
@Tuzo : 맞습니다. 이것이 바로 GC.KeepAlive의 목표입니다.
Steven Sudit 2016 년

1
@Craig Johnston : 아니요. .NET 런타임이 당신을 위해 그것을 관리하고 좋은 일을하기 때문에 아닙니다. 프로그래머가해야 할 일은 컴파일 만하 코드를 작성하는 것이 아니라 실행되는 코드를 작성하는 것이기 때문 입니다. 경우에 따라 런타임에서 수행중인 작업을 파악하는 데 도움이 될 수 있습니다 (예 : 문제 해결). 훌륭한 프로그래머와 훌륭한 프로그래머를 분리하는 데 도움이되는 지식 유형이라고 주장 할 수 있습니다.
랜디는 Monica

18

다른 사람들이 말했듯이 Dispose클래스가 구현 하면 분명히 전화하고 싶습니다 IDisposable. 나는 이것에 대해 상당히 엄격한 입장을 취합니다. 일부 세력의 주장은 호출하는 것을 DisposeDataSet그들은 그것을 분해하고 의미있는 아무것도하지 않았다는 것을 보았 기 때문에, 예를 들어, 무의미하다. 그러나 나는 그 주장에 오류가 많다고 생각합니다.

주제에 대해 존경받는 사람들의 흥미로운 토론에 대해 읽으십시오 . 그런 다음 Jeffery Richter가 잘못된 캠프에 있다고 생각하는 이유를 여기에서 읽으십시오 .

이제 참조를로 설정해야하는지 여부를 결정합니다 null. 내 대답은 아니오 야. 다음 코드로 요점을 설명하겠습니다.

public static void Main()
{
  Object a = new Object();
  Console.WriteLine("object created");
  DoSomething(a);
  Console.WriteLine("object used");
  a = null;
  Console.WriteLine("reference set to null");
}

그렇다면 언제 참조하는 객체 a를 수집 할 수 있다고 생각 하십니까? 당신이 전화 후 말했다면 당신 a = null은 잘못입니다. Main방법이 완료된 후에 말한 경우 에도 잘못된 것입니다. 정답은 에 전화하는 동안 언젠가 수금 자격이 있다는 것입니다 DoSomething. 맞아 그거야. 그것은 자격이 되기 전에 참조로 설정 null도 호출하기 전에 아마 및 DoSomething완료. JIT 컴파일러는 객체 참조가 아직 루팅되어 있어도 더 이상 참조 해제되지 않는 경우를 인식 할 수 있기 때문입니다.


3
어떤 경우 a클래스의 private 멤버 필드는 무엇입니까? 경우 anull로 설정되지 않은 GC는 경우 알 수있는 방법이 없습니다 a바로, 어떤 방법으로 다시 사용됩니다? 따라서 a포함하는 전체 클래스가 수집 될 때까지 수집되지 않습니다. 아니?
Kevin P. Rice

4
@ 케빈 : 맞습니다. 경우 a클래스 멤버이었고 클래스 함유 a여전히 뿌리되었으며에서 사용 후 너무 놀아 것이다. 그것이 설정하는 null것이 유익 할 수있는 하나의 시나리오 입니다.
Brian Gideon

1
당신의 요점 Dispose은 중요한 이유와 Dispose관련이 있습니다. 뿌리에 대한 참조가없는 객체 에서 호출 할 수 없습니다 (또는 다른 인라인 할 수없는 방법). Dispose객체를 사용하여 호출 한 후 호출 하면 루팅 된 참조가 마지막으로 수행 된 작업이 지속되는 동안 계속 존재합니다. 호출하지 않고 객체에 대한 모든 참조를 포기하면 Dispose아이러니하게도 객체의 리소스가 때때로 너무 일찍 해제 될 수 있습니다 .
supercat

이 예제와 설명은 참조를 null로 설정하지 않는다는 어려운 제안에서 결정적인 것으로 보이지 않습니다. 내가 케빈의 코멘트를 제외하고, 의미, 널 (null)에 대한 참조 세트 가 배치 된 후에는 꽤 보인다 양성 , 그래서 해가 무엇인가? 뭔가 빠졌습니까?
dathompson

13

C #에서 개체를 null로 설정할 필요는 없습니다. 컴파일러와 런타임은 더 이상 범위에 속하지 않을 때 알아서 처리합니다.

예, IDisposable을 구현하는 객체를 폐기해야합니다.


2
큰 객체에 대한 오래 지속 된 (또는 정적) 참조가있는 want경우이를 확보 한 후이를 즉시 회수 할 수 있도록 null 처리해야합니다.
Steven Sudit 2016 년

12
"완료"되었다면 정적이지 않아야합니다. 정적이지 않지만 "오래 지속되는"경우에는 작업을 마친 후에도 여전히 범위를 벗어나야합니다. 참조를 null로 설정해야한다는 것은 코드 구조에 문제가 있음을 나타냅니다.
EMP

당신은 당신이 완료 정적 항목을 가질 수 있습니다. 다음을 고려하십시오. 사용자 친화적 인 형식으로 디스크에서 읽은 다음 프로그램 사용에 적합한 형식으로 구문 분석되는 정적 자원. 더 이상 사용되지 않는 원시 데이터의 개인 사본으로 끝날 수 있습니다. (실제 예 : 파싱은 두 단계로 진행되므로 데이터를 읽을 때 간단히 처리 할 수 ​​없습니다.)
Loren Pechtel

1
그런 다음 임시로만 사용되는 경우 원시 필드를 정적 필드에 저장해서는 안됩니다. 물론, 그렇게 할 수 있습니다. 정확히 이런 이유로 좋은 습관은 아닙니다. 그런 다음 수명을 수동으로 관리해야합니다.
EMP

2
원시 데이터를 처리하는 메소드에서 원시 변수를 로컬 변수에 저장하여이를 피할 수 있습니다. 이 메소드는 처리 된 데이터를 리턴하지만 유지 한 데이터는 메소드가 종료되고 자동으로 GC 될 때 원시 데이터의 로컬 범위를 벗어납니다.
EMP

11

나는 일반적인 대답에 동의합니다. 그렇습니다. 처분해야하며 일반적으로 변수를 null로 설정해서는 안됩니다 ...하지만 처분은 주로 메모리 관리에 관한 것이 아니라고 지적하고 싶습니다. 그렇습니다. 메모리 관리에 도움이 될 수도 있고 때로는 도움이 될 수도 있지만, 주된 목적은 부족한 리소스를 결정적으로 해제하는 것입니다.

예를 들어, 하드웨어 포트 (예 : 직렬), TCP / IP 소켓, 파일 (독점 액세스 모드) 또는 데이터베이스 연결을 열면 다른 코드가 해제 될 때까지 해당 항목을 사용하지 못하게되었습니다. Dispose는 일반적으로 이러한 항목을 릴리스합니다 (GDI 및 기타 "os"핸들과 함께 1000 개가 있지만 여전히 전체적으로 제한됨). 소유자 개체에 대해 dipose를 호출하지 않고 이러한 리소스를 명시 적으로 해제 한 경우 나중에 처리되지 않은 수집되지 않은 개체에 여전히 항목이 열려 있기 때문에 열기 시도가 실패하는 동일한 리소스를 다시 열거 나 다른 프로그램에서 다시 시도하십시오. . 물론, GC가 아이템을 수집 할 때 (Dispose 패턴이 올바르게 구현 된 경우) 리소스가 해제 될 것입니다.하지만 그 시점이 언제인지 알지 못하므로 해당 리소스를 다시 열어도 안전한지 알 수 없습니다. 이것은 Dispose가 해결하는 주요 문제입니다. 물론, 이러한 핸들을 해제하면 종종 메모리도 해제되고, 해제하지 않으면 해당 메모리가 해제되지 않을 수 있습니다. 따라서 메모리 누수 또는 메모리 정리 지연에 대한 모든 이야기가 있습니다.

나는 이것이 문제를 일으키는 실제 사례를 보았습니다. 예를 들어, SQL 서버의 '연결 풀이 가득 찼기'때문에 ASP.Net 웹 응용 프로그램이 결국 데이터베이스에 연결하지 못하는 경우를 보았습니다 (짧은 시간이나 웹 서버 프로세스가 다시 시작될 때까지). 너무 많은 연결이 생성되어 너무 짧은 시간 내에 명시 적으로 해제되지 않아서 새로운 연결을 만들 수 없으며 풀의 많은 연결이 활성 상태는 아니지만 여전히 미 확산 및 수집되지 않은 개체에 의해 참조되므로 재사용하지 마십시오. (당신이하지 않으면되지 적어도 올바르게 필요한 보장하지만이 문제가 발생하지 않습니다 데이터베이스 연결을 폐기 매우 높은 동시 액세스).


11

객체가를 구현 IDisposable하면 예, 처리해야합니다. 개체가 즉시 해제되지 않을 수있는 기본 리소스 (파일 핸들, OS 개체)에 걸려있을 수 있습니다. 이로 인해 리소스 부족, 파일 잠금 문제 및 피할 수있는 기타 미묘한 버그가 발생할 수 있습니다.

MSDN 에서 Dispose Method 구현을 참조하십시오 .


그러나 가비지 콜렉터는 Dispose ()를 호출하지 않습니까? 그렇다면 왜 전화해야합니까?
CJ7

명시 적으로 호출하지 않으면 호출 Dispose될 것이라는 보장이 없습니다 . 또한 개체가 부족한 리소스를 보유하고 있거나 일부 리소스 (예 : 파일)를 잠그는 경우 가능한 한 빨리 해제해야합니다. GC가 그렇게하기를 기다리는 것은 차선책입니다.
Chris Schmich

12
GC는 Dispose ()를 호출하지 않습니다. GC는 규칙에 따라 리소스를 정리해야하는 종료자를 호출 할 수 있습니다.
adrianm

@adrianm : might전화 하지 않고 전화 will하십시오.
leppie

2
@leppie : 종료자는 결정적이지 않으며 호출되지 않을 수 있습니다 (예 : appdomain이 언로드 될 때). 결정 론적 마무리가 필요한 경우 중요한 처리기라고 생각되는 것을 구현해야합니다. CLR은 이러한 객체를 특수하게 처리하여 객체가 최종화되도록 보장합니다 (예 : 메모리 부족을 처리하기 위해 최종 코드를 미리 생성 함)
adrianm

9

이들이 IDisposable 인터페이스를 구현하는 경우이를 폐기해야합니다. 가비지 수집기가 나머지를 처리합니다.

편집 :using 일회용 항목으로 작업 할 때 명령 을 사용하는 것이 가장 좋습니다 .

using(var con = new SqlConnection("..")){ ...

5

객체가 구현되면 IDisposable당신이 호출해야합니다 Dispose(또는 Close경우에, 그것은 당신을 위해 폐기를 호출합니다).

nullGC는 객체를 더 이상 사용하지 않을 것임을 알기 때문에 일반적으로 객체를로 설정하지 않아도됩니다 .

객체를로 설정하면 한 가지 예외가 있습니다 null. 작업해야 할 많은 객체 (데이터베이스에서)를 검색하여 컬렉션 (또는 배열)에 저장합니다. "작업"이 완료되면 nullGC에서 작업이 완료되었음을 알지 못하기 때문에 객체를로 설정 했습니다.

예:

using (var db = GetDatabase()) {
    // Retrieves array of keys
    var keys = db.GetRecords(mySelection); 

    for(int i = 0; i < keys.Length; i++) {
       var record = db.GetRecord(keys[i]);
       record.DoWork();
       keys[i] = null; // GC can dispose of key now
       // The record had gone out of scope automatically, 
       // and does not need any special treatment
    }
} // end using => db.Dispose is called

4

일반적으로 필드를 null로 설정할 필요는 없습니다. 그러나 항상 관리되지 않는 리소스를 폐기하는 것이 좋습니다.

경험을 바탕으로 다음을 수행하는 것이 좋습니다.

  • 더 이상 필요하지 않은 이벤트를 구독 취소하십시오.
  • 더 이상 필요하지 않으면 대리자 또는 표현식을 보유하는 필드를 null로 설정하십시오.

위의 조언을 따르지 않은 직접적인 결과 인 문제를 찾기가 매우 어려웠습니다.

이를 수행하기에 좋은 곳은 Dispose ()에 있지만 일반적으로 빠를수록 좋습니다.

일반적으로 객체에 대한 참조가 존재하면 가비지 수집기 (GC)는 객체가 더 이상 사용되지 않는다는 것을 알아 내기 위해 몇 세대 더 걸릴 수 있습니다. 모든 객체는 메모리에 남아 있습니다.

앱이 예상보다 많은 메모리를 사용하고 있음을 알 때까지는 문제가되지 않을 수 있습니다. 이 경우 메모리 프로파일 러를 연결하여 정리되지 않은 개체를 확인하십시오. 다른 객체를 참조하는 필드를 null로 설정하고 폐기시 컬렉션을 지우면 GC가 메모리에서 제거 할 수있는 객체를 파악하는 데 실제로 도움이됩니다. GC는 사용 된 메모리를 더 빨리 회수하여 앱의 메모리 사용량이 적고 빠릅니다.


1
'이벤트 및 델리게이트'에 대해 무엇을 의미합니까? 이것으로 '정리'해야하는 것은 무엇입니까?
CJ7

@Craig-답변을 편집했습니다. 잘만되면 이것은 그것을 조금 분명히합니다.
Marnix van Valen

3

항상 dispose를 호출하십시오. 위험할만한 가치가 없습니다. 대규모 관리되는 엔터프라이즈 응용 프로그램은 존중해야합니다. 어떤 가정도 할 수 없으며, 그렇지 않으면 다시 물릴 것입니다.

leppie의 말을 듣지 마십시오.

많은 객체가 실제로 IDisposable을 구현하지 않기 때문에 걱정할 필요가 없습니다. 이들이 실제로 범위를 벗어나면 자동으로 해제됩니다. 또한 무언가를 null로 설정 해야하는 상황을 결코 보지 못했습니다.

일어날 수있는 한 가지는 많은 객체가 열린 채로있을 수 있다는 것입니다. 이렇게하면 응용 프로그램의 메모리 사용량이 크게 증가 할 수 있습니다. 때때로 이것이 실제로 메모리 누수인지 아니면 응용 프로그램이 많은 일을하고 있는지 여부를 해결하기가 어렵습니다.

메모리 프로파일 도구는 그러한 것들에 도움이 될 수 있지만 까다로울 수 있습니다.

또한 필요하지 않은 이벤트는 항상 구독 취소하십시오. 또한 WPF 바인딩 및 컨트롤에주의하십시오. 일반적인 상황은 아니지만 기본 개체에 바인딩 된 WPF 컨트롤이있는 상황을 겪었습니다. 기본 개체가 커서 많은 양의 메모리를 차지했습니다. WPF 컨트롤이 새 인스턴스로 바뀌고 있었고 이전 인스턴스는 여전히 어떤 이유로 걸려있었습니다. 이로 인해 큰 메모리 누수가 발생했습니다.

후부 사이트에서 코드가 잘못 작성되었지만 요점은 사용되지 않는 항목이 범위를 벗어 났는지 확인하려는 것입니다. 메모리의 어떤 것이 유효한지, 어떤 것이 없어야하는지 알기가 어렵 기 때문에 메모리 프로파일 러를 찾는 데 오랜 시간이 걸렸습니다.


2

나도 대답해야한다. JIT는 변수 사용에 대한 정적 분석을 통해 코드와 함께 테이블을 생성합니다. 이러한 테이블 항목은 현재 스택 프레임에서 "GC- 루트"입니다. 명령 포인터가 진행되면 해당 테이블 항목이 유효하지 않게되어 가비지 수집 준비가됩니다. 따라서 범위 변수 인 경우 변수를 null로 설정할 필요가 없습니다. GC가 개체를 수집합니다. 멤버 또는 정적 변수 인 경우 널로 설정해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.