176

모든 객체를로 설정해야합니까?null(NothingVB.NET에서) 일단 당신이 그들과 함께 끝냈습니까?

NET에서 그것을 구현하는 개체의 인스턴스를 처리하는 것이 필수적입니다.IDisposable객체가 처리 된 후에도 여전히 무언가가 될 수 있지만 일부 리소스를 해제하는 인터페이스isDisposed양식의 속성), 그래서 그것은 여전히 메모리 또는 적어도 부분적으로 상주 할 수 있다고 가정합니까?

또한 객체가 범위를 벗어날 때 가비지 컬렉터의 다음 단계를 위해 컬렉션을 위해 표시된다는 것을 알고 있습니다 (시간이 걸릴 수도 있음).

따라서 이것을 염두에두고null시스템이 더 이상 범위를 벗어나고 나쁜 부작용이 없다는 사실을 기억할 필요가 없으므로 시스템의 속도를 높일 수 있습니까?

MSDN 기사는 예제에서는이 작업을 수행하지 않으며 현재로서는이 작업을 수행 할 수 없습니다. 해를보십시오. 그러나 의견이 섞여서 어떤 의견이라도 유용합니다.


  • +1 큰 질문. 누구든지 컴파일러가 과제를 모두 최적화하는 상황을 알고 있습니까? 즉 누군가 다른 상황에서 MSIL을 보았고 객체를 null (또는 그 부족)으로 설정 한 IL을 지적했습니다. - Tim Medora

13 답변


67

Karl은 절대적으로 정확합니다. 사용 후 객체를 null로 설정할 필요가 없습니다. 객체가 구현 된 경우IDisposable, 당신이 전화했는지 확인하십시오.IDisposable.Dispose()그 물건으로 끝내면 (try..finally, 또는 ausing()블록). 하지만 전화를하지 않은 경우에도Dispose(), 개체의 finalizer 메서드는 호출해야합니다.Dispose()너를 위해서.

나는 이것이 좋은 치료라고 생각 :

IDisposable 파기

IDisposable 이해하기

자체 조정 및 불투명이기 때문에 GC 및 관리 전략을 추측 해 볼 필요가 없습니다. 제프리 리히터 (Dot Net Rocks)의 내부 작업에 대한 좋은 토론이있었습니다.Jeffrey Richter, Windows 메모리 모델과 판사의 서적C #을 통한 CLR20 장은 훌륭한 치료법입니다 :


  • null로 설정하지 않는 것에 대한 규칙은 "어렵고 빠름"이 아닙니다 ... 오브젝트가 대형 오브젝트 힙 (크기가 85K보다 큼)에 놓이면 오브젝트를 널 (NULL)로 설정하면 GC에 도움이됩니다 당신이 그것을 사용하여 완료되면. - Scott Dorman
  • 제한된 범위에 동의하지만, 메모리 부족 현상이 발생하지 않으면 조기에 최적화 할 필요가 없습니다. ' 사용 후에 객체를 null로 설정합니다. - Kev
  • " 조기에 최적화하지 마라 " " CPU 속도가 빨라지고 CRUD 앱의 속도가 빨라지므로 걱정하지 마세요. "와 같은 소리가납니다. " 그것은 나일지도 모른다. :) - BobbyShaftoe
  • 이것이 의미하는 바는 " 가비지 수집기가 당신보다 메모리를 관리하는 것이 더 낫다는 것입니다. " 그게 나일지도 몰라. :) - BobRodes
  • @BobbyShaftoe : "조기 최적화가 항상 나쁘다"라고 말하는 것이 잘못되었습니다. " 느린 &을 선호합니다. "의 반대편 극단으로 점프하기 때문입니다. 합리적인 프로그래머도 말할 수 없습니다. 최적화에 대한 뉘앙스와 현명한 생각입니다. 개인적으로 코드 명확성에 대해 개인적으로 염려하고 직접 테스트 한 결과 (내가 어렸을 때 나 자신을 포함하여 많은 사람들이 개인적으로 보았 듯이) "너무"많은 시간을 들여 "완벽하게"만들었습니다. 알고리즘을 사용하여 가독성이 완전히 발휘되는 동안 만 100,000 반복에서 0.1ms를 절약했습니다. - Brent Rittenhouse

34

작업을 마쳤을 때 객체를 null로 설정하지 않는 또 다른 이유는 실제로 객체를 오래 유지할 수 있다는 것입니다.

을 포함한다.

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

someType에 의해 참조 된 객체가 "DoSomething"을 호출 한 후 GC 될 수 있습니다.

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

메소드의 끝까지 객체를 유지할 수 있습니다. 그만큼JIT는 일반적으로 할당을 null로 최적화합니다.따라서 두 비트의 코드는 모두 동일하게됩니다.


  • 그 점이 흥미로운 점입니다. 나는 항상 대상이 범위를 벗어나는 방법이 끝날 때까지 범위를 벗어나지 않을 것이라고 생각했습니다. 물론 개체가 Use 블록 내에서 범위가 지정되거나 명시 적으로 Nothing 또는 null로 설정되어 있지 않은 한. - Guru Josh
  • 그들이 살아남을 수있는 좋은 방법은GC.KeepAlive(someType);만나다ericlippert.com/2013/06/10/construction-destruction - NotMe

15

객체를 null로 설정하지 마십시오. 체크 아웃 할 수 있습니다.http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx더 많은 정보를 원한다면, 당신의 코드를 더티 (dirty)하는 것을 제외하고는, 아무 것도하지 않는다.


  • 공유 링크의 메모리에 대한 세부 묘사 - user2323308

7

또한:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of


7

일반적으로 사용 후 객체를 null로 할 필요는 없지만 경우에 따라 객체를 사용하는 것이 좋습니다.

개체가 IDisposable을 구현하고 필드에 저장되어있는 경우 폐기 된 개체를 사용하지 않으려면 null로 설정하는 것이 좋습니다. 다음 종류의 버그는 고통 스러울 수 있습니다.

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

필드를 삭제 한 후에 필드를 null로 설정하고 필드가 다시 사용되는 행에서 NullPtrEx 권한을 얻는 것이 좋습니다. 그렇지 않으면, DoSomething이하는 일에 따라 줄을 따라 일부 위험한 버그가 발생할 수 있습니다.


  • 이미 배치 된 객체는 이미 삭제 된 경우 ObjectDisposedException을 throw해야합니다. 이것은 내가 아는 한 모든 곳에서 상용구 코드가 필요하지만, 다시 말하면 Disposed는 나쁘게 생각한 패러다임이다. - nicodemus13
  • Ctrl + F 키.Dispose(). 찾으면 IDisposable을 올바르게 사용하지 않습니다. 일회용 물체의 유일한 용도는 사용 블록의 경계에 있어야합니다. 그리고 using-block을 사용하면myField더 이상. 그리고 using 블록 내에서null필요하지 않으면 using-block은 객체를 처리합니다. - Suamere

7

코드의 필요성을 느낀다면 코드가 충분히 구조화되지 않을 가능성이 있습니다.null변수.

변수의 범위를 제한하는 데는 여러 가지 방법이 있습니다.

언급 한 바와 같이스티브 트란 비

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

비슷하게 중괄호를 사용할 수도 있습니다.

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

코드를 실제로 없애고 이해하기 쉽도록 "제목"없이 중괄호를 사용하는 것을 발견했습니다.


  • 나는 커스텀 로컬 스코프 (smarta $$)를 한번 사용해 보았다. 회사가 폭발했습니다. - Suamere
  • 또 다른 참고 사항 : 이것은 C #컴파일러가 IDisposable을 구현하는 지역 범위 변수를 찾고 해당 범위가 끝나는 .Dispose (MOST 중)를 호출하기 때문입니다. 그러나 ... SQL 연결은 .Dispose ()가 절대로 최적화되지 않은 중요한 시간입니다. 명확한주의가 필요한 몇 가지 유형이 있으므로 개인적으로 항상 명시 적으로 일을 처리하므로 물지는 않습니다. - Suamere

5

변수를 null로 설정해야하는 유일한 경우는 변수가 범위를 벗어나 더 이상 관련 데이터가 필요하지 않을 때입니다. 그렇지 않으면 필요가 없습니다.


  • 물론 사실이지만 코드를 리팩토링해야합니다. 변수의 범위를 벗어나는 변수를 선언해야한다고 생각하지 않습니다. - Karl Seguin
  • "변수" 객체 필드를 포함하는 것으로 이해되면이 대답은 많은 의미를 갖습니다. "변수"가 " "로컬 변수"는 단지 "로컬 변수" (방법 중 하나 인 경우) 여기에서 틈새 시장에 대해 이야기하고 있습니다 (예 : 평소보다 훨씬 긴 시간 동안 실행되는 방법). - stakx

5

일반적으로 null로 설정할 필요가 없습니다. 그러나 클래스에 리셋 기능이 있다고 가정 해보십시오.

Dispose를 올바르게 구현하지 못하고 System.ObjectDisposed 예외를 throw 할 수 있으므로 Dispose를 두 번 호출하지 않으려 고하기 때문에 수행 할 수 있습니다.

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }


3

이런 종류의 "사용 후에 객체를 null로 설정할 필요가 없습니다"는 완전히 정확하지는 않습니다. 변수를 삭제 한 후에 NULL을 사용해야하는 경우가 있습니다.

예, 항상 통화해야합니다..Dispose()또는.Close()당신이 끝났을 때 가지고있는 모든 것에. 파일 핸들, 데이터베이스 연결 또는 일회용 개체 일 수 있습니다.

그것과는 별도로 LazyLoad의 실용적인 패턴이 있습니다.

내가 인스턴스화했다고 가정 해 보겠습니다.ObjAclass A.Class A공개 재산이있다.PropBclass B.

내부적으로,PropB개인 변수를 사용합니다._B기본값은 null입니다. 언제PropB.Get()이 (가) 사용되면_PropBnull 인 경우는, 인스턴스를 생성하는데 필요한 자원을 엽니 다.B으로_PropB. 그런 다음 반환합니다._PropB.

내 경험에 비추어 볼 때 이것은 정말 유용한 트릭입니다.

null 값의 필요성은 A를 재설정하거나 A의 내용을 어떤 식으로 변경하면_PropB이전 값의 아이였다.A, 당신은 폐기해야합니다 및 null을_PropB따라서 LazyLoad는 코드에서 필요로하는 경우 올바른 값을 가져 오도록 재설정 할 수 있습니다.

너만하면_PropB.Dispose()LazyLoad에 대한 null 검사가 성공할 것으로 예상되면 잠시 후 NULL이되지 않으며 부실 데이터가 표시됩니다. 사실상,Dispose()확인차.

나는 그것이 틀림없이 있었으면 좋았을 텐데, 나는 지금이 행동을 보여주는 코드를 가지고있다.Dispose()~에_PropB그리고 Dispose를 수행 한 호출 함수 외부에서 (따라서 범위를 벗어나서) private prop는 여전히 null이 아니며 부실 데이터는 여전히 존재합니다.

결국 폐기 된 속성은 null이되지만 내 관점에서는 비 결정적입니다.

핵심 이유는 dbkk에서 알 수 있듯이 상위 컨테이너 (ObjAPropB)의 인스턴스를 유지하고있다._PropB범위에도 불구하고,Dispose().


  • 수동으로 null로 설정하는 것이 발신자에게 치명적인 오류를 발생시키는 것을 좋은 예로 보여주는 좋은 예입니다. - rolls

1

참조를 null로하는 것이 의미있는 경우가 있습니다. 예를 들어, 우선 순위 대기열과 같은 콜렉션을 작성하고 계약서를 작성할 때, 클라이언트가 대기열에서 해당 오브젝트를 제거한 후에는 클라이언트에 대해 해당 오브젝트를 활성 상태로 유지하지 않아야합니다.

그러나 이런 종류의 것은 오랫동안 살아온 컬렉션에서만 중요합니다. 대기열이 생성 된 함수의 끝에서 생존하지 못한다면 전체적으로 훨씬 덜 중요합니다.

전반적으로, 당신은 정말로 신경 쓰지 않아야합니다. 컴파일러와 GC가 당신의 일을 할 수있게하십시오.


1

이 기사를 살펴보십시오.http://www.codeproject.com/KB/cs/idisposable.aspx

대부분의 경우, 오브젝트를 null로 설정해도 효과는 없습니다. 이렇게해야하는 유일한 시간은 크기가 84K (비트 맵)보다 큰 "대형 오브젝트"로 작업하는 경우입니다.


0

GC 구현 자의 설계에 의해 믿을 수 없다.속도를 올리다무효화 된 GC. GC를 실행하는 방법 / 방법에 대해 걱정하지 않으려 고합니다. 유비쿼터스처럼 취급하십시오.존재너를 보호하고 지켜 보며 ... (머리를 숙이고 하늘로 주먹을니다) ...

개인적으로, 나는 셀프 문서화의 형태로 변수를 다룰 때 변수를 null로 명시 적으로 설정합니다. 선언하고, 사용하고, 나중에 null로 설정하지 않습니다. 더 이상 필요하지 않으면 즉시 null입니다. 나는 분명히 말합니다, "나는 공식적으로 너와 끝났어 ... 가버 리다."

GC 된 언어에서 무효화가 필요합니까? 아닙니다. GC에 도움이됩니까? 어쩌면 예, 어쩌면 아니요, 확실하지 않습니다. 설계 상으로는 제어 할 수 없으며, 현재 버전의 응답 또는 미래의 GC 구현에 관계없이 미래의 GC 구현은 제 제어 범위를 벗어나는 응답을 변경할 수 있습니다. 또한 nulling이 최적화 된 경우 더 멋지다.논평당신이 원한다면.

내 발걸음을 따라가는 다음 가난한 바보에게 나의 의도가 더 명확하게 드러난다면"힘"잠재적으로 GC를 도움이되는 경우, 나에게 가치있는 것입니다. 대부분 그것이 나를 깔끔하고 깨끗하게 느끼게하고 몽고는 깔끔하고 깨끗하게 느끼기를 좋아합니다. :)

나는 이것을 다음과 같이 보았다 : 사람들이 다른 사람들에게 의도와 컴파일러에 대해 무엇을해야하는지에 대한 아이디어를주기 위해 프로그래밍 언어가 존재한다 - 컴파일러는 그 요청을 다른 언어 (때로는 여러 가지)로 CPU로 변환한다. CPU는 당신이 사용한 언어, 탭 설정, 주석, 문체 강조, 변수 이름 등을 알려줄 수 있습니다. CPU는 모든 레지스터와 opcode 및 메모리 위치가 왜곡되는지를 알려주는 비트 스트림에 관한 것입니다. 코드로 작성된 많은 것들은 우리가 지정한 순서대로 CPU에 의해 소비되는 것으로 변환되지 않습니다. 우리의 C, C ++, C #, Lisp, Babel, 어셈블러 또는 실제가 아닌 이론이면서 작업의 성명서로 쓰여진 것. 보시다시피, 어셈블러 언어로도 얻을 수있는 것은 아닙니다.

나는 "불필요한 것들"(빈 줄과 같은)의 사고 방식을 이해하지만 "잡음과 혼란스런 코드 일뿐입니다." 저의 경력은 저였습니다. 나는 그것을 완전히 얻는다. 이 시점에서 나는 코드를 명확하게 만드는 방향으로 기울어진다. 내 프로그램에 50 줄의 "노이즈"를 추가하는 것과는 다릅니다. 여기 또는 저기에 몇 줄이 있습니다.

규칙에는 예외가 있습니다. 휘발성 메모리, 정적 메모리, 경쟁 조건, 싱글 톤, "오래된"데이터 사용 및 이와 같은 모든 종류의 썩음 현상이있는 시나리오에서는 다른 점이 있습니다. 자신의 메모리를 관리해야하며, 메모리가 일부가 아니기 때문에 잠금 및 무효화가 필요합니다. GC'd Universe - 잘하면 모두가 그것을 이해합니다. 나머지 시간은 GC'd 언어로되어있어 필요성이나 성능 향상이 아닌 스타일의 문제입니다.

하루가 끝나면 GC 자격 요건에 대해 이해하고 있는지 확인하십시오. 적절하게 잠금, 처리 및 무효화; 왁스를 켜고 왁스를 내린다. 숨을들이 쉬고 내쉬세요; 그리고 내가 말하는 모든 것에 대해 : 기분이 좋으면 그것을하십시오. 귀하의 마일리지가 달라질 수 있습니다 ...


-1

어떤 객체는.dispose()메모리에서 리소스를 강제로 제거하는 메서드입니다.


  • 아닙니다. Dispose () 않습니다.아니개체를 수집합니다. 일반적으로 관리되지 않는 리소스를 해제하는 결정적 정리를 수행하는 데 사용됩니다. - Marc Gravell
  • 결정론은 관리되는 리소스에만 적용되며 관리되지 않는 리소스 (예 : 메모리)에는 적용되지 않습니다. - nicodemus13

연결된 질문


관련된 질문

최근 질문