문제

모든 개체를 다음으로 설정해야 합니까? null (Nothing VB.NET에서) 작업을 마친 후에는 어떻게 되나요?

.NET에서는 다음을 구현하는 개체의 인스턴스를 모두 삭제하는 것이 필수적이라는 것을 이해합니다. IDisposable 객체가 삭제된 후에도 여전히 무언가일 수 있지만 일부 리소스를 해제하기 위한 인터페이스(따라서 isDisposed 속성), 그래서 나는 그것이 여전히 메모리에 있거나 적어도 부분적으로 존재할 수 있다고 가정합니까?

또한 개체가 범위를 벗어나면 가비지 수집기의 다음 단계를 위해 수집 준비가 된 것으로 표시된다는 것도 알고 있습니다(시간이 걸릴 수 있음).

따라서 이를 염두에 두고 다음과 같이 설정합니다. null 메모리가 더 이상 범위에 속하지 않으며 나쁜 부작용이 있는지 확인할 필요가 없으므로 시스템에서 메모리를 해제하는 속도를 높이나요?

MSDN 기사는 예제 에서이 작업을 수행하지 않으며 현재 해를 볼 수 없으므로이 작업을 수행합니다.그러나 나는 의견이 혼합되어 있으므로 모든 의견이 유용합니다.

도움이 되었습니까?

해결책

Karl은 절대적으로 정확합니다. 사용 후에 객체를 null로 설정할 필요가 없습니다.객체가 구현하는 경우 IDisposable, 꼭 전화해 보세요 IDisposable.Dispose() 해당 개체 작업이 완료되면( try..finally, 또는 using() 차단하다).하지만 전화하는 걸 기억하지 못하더라도 Dispose(), 객체의 종료자 메서드가 호출되어야 합니다. Dispose() 당신을 위한.

나는 이것이 좋은 치료법이라고 생각했습니다.

IDisposable 자세히 알아보기

IDisposable 이해

GC와 관리 전략은 자체 조정되고 불투명하기 때문에 다시 추측하는 것은 의미가 없습니다.여기 Dot Net Rocks에서 Jeffrey Richter와의 내부 작업에 대한 좋은 토론이 있었습니다. Windows 메모리 모델에 대한 Jeffrey Richter 그리고 Richters Book C#을 통한 CLR 20장에는 훌륭한 치료법이 있습니다:

다른 팁

작업을 마친 후 개체를 null로 설정하지 않는 또 다른 이유는 실제로 개체를 더 오랫동안 활성 상태로 유지할 수 있다는 것입니다.

예를 들어

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

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

"DoSomething" 호출 후에 someType이 참조하는 객체가 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 할당을 최적화합니다., 따라서 두 코드 비트 모두 동일하게 됩니다.

아니요, 개체를 null로 만들지 마세요.확인하실 수 있습니다 http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx 자세한 내용은 null로 설정해도 코드가 더러워지는 것 외에는 아무 작업도 수행되지 않습니다.

또한:

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

일반적으로 사용 후 개체를 null로 설정할 필요는 없지만 어떤 경우에는 이것이 좋은 방법이라고 생각합니다.

개체가 IDisposable을 구현하고 필드에 저장되는 경우 삭제된 개체를 사용하지 않으려면 null을 사용하는 것이 좋다고 생각합니다.다음과 같은 종류의 버그는 고통스러울 수 있습니다.

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

필드를 처리한 후 해당 필드를 null로 설정하고 해당 필드가 다시 사용되는 줄에서 바로 NullPtrEx를 가져오는 것이 좋습니다.그렇지 않으면 DoSomething이 수행하는 작업에 따라 몇 가지 비밀스러운 버그가 발생할 수 있습니다.

필요하다고 생각되면 코드가 충분히 긴밀하게 구성되어 있지 않을 가능성이 있습니다. 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

"제목" 없이 중괄호를 사용하면 코드를 깔끔하게 정리하고 이해하기 쉽게 만드는 데 도움이 됩니다.

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

일반적으로 null로 설정할 필요가 없습니다.하지만 수업에 재설정 기능이 있다고 가정해 보세요.

그런 다음 Dispose 중 일부가 올바르게 구현되지 않고 System.ObjectDisposed 예외가 발생할 수 있으므로 dispose를 두 번 호출하고 싶지 않기 때문에 그렇게 할 수 있습니다.

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

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

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

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

내가 가지고 있고 인스턴스화했다고 가정하십시오. ObjA ~의 class A. Class A 다음과 같은 공공 자산이 있습니다. PropB ~의 class B.

내부적으로는 PropB 개인 변수를 사용합니다 _B 기본값은 null입니다.언제 PropB.Get() 사용되었는지 확인합니다. _PropB null이고 null인 경우 인스턴스화에 필요한 리소스를 엽니다. B ~ 안으로 _PropB.그런 다음 반환됩니다. _PropB.

내 경험상 이것은 정말 유용한 트릭이다.

null이 필요한 곳은 A의 내용을 어떤 방식으로든 재설정하거나 변경하는 경우입니다. _PropB 이전 값의 하위 항목이었습니다. A, Dispose 및 null out이 필요합니다. _PropB 따라서 LazyLoad는 코드에서 요구하는 경우 올바른 값을 가져오기 위해 재설정할 수 있습니다.

하기만 하면 _PropB.Dispose() LazyLoad에 대한 null 검사가 성공할 것으로 예상한 직후에는 null이 아니며 오래된 데이터를 보게 됩니다.실제로는 다음 이후에 null로 설정해야 합니다. Dispose() 확인차.

나는 확실히 그렇지 않았으면 좋겠지만 지금 당장 이 동작을 나타내는 코드를 가지고 있습니다. Dispose()_PropB Dispose를 수행한 호출 함수 외부(따라서 거의 범위를 벗어남)에서는 private prop이 여전히 null이 아니며 오래된 데이터가 여전히 존재합니다.

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

dbkk가 암시하는 핵심 이유는 상위 컨테이너(ObjA ~와 함께 PropB)는 다음의 인스턴스를 유지하고 있습니다. _PropB 범위 내에도 불구하고 Dispose().

null 참조가 적합한 경우도 있습니다.예를 들어, 우선 순위 큐와 같은 컬렉션을 작성할 때 계약에 따라 클라이언트가 큐에서 개체를 제거한 후에 해당 개체를 클라이언트에 대해 활성 상태로 유지해서는 안 됩니다.

그러나 이런 종류의 일은 오래 지속되는 컬렉션에서만 중요합니다.큐가 생성된 함수가 끝난 후에도 큐가 유지되지 않는다면 그것은 훨씬 덜 중요합니다.

전체적으로, 당신은 정말로 귀찮게해서는 안됩니다.컴파일러와 GC가 작업을 수행하도록 하여 귀하가 원하는 대로 작업을 수행하도록 하십시오.

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

대부분의 경우 개체를 null로 설정해도 아무런 효과가 없습니다.반드시 그렇게 해야 하는 유일한 경우는 크기가 84K보다 큰 "대형 개체"(예: 비트맵)로 작업하는 경우입니다.

Stephen Cleary는 이 게시물에서 매우 잘 설명합니다. 가비지 수집을 지원하려면 변수를 Null로 설정해야 합니까?

말한다:

변수가 정적 필드이거나 열거 가능한 방법 (수율 반환 사용) 또는 비동기 메소드 (비동기 및 기다리고 있음)를 작성하는 경우 짧은 답변.그렇지 않으면 그렇지 않습니다.

즉, 일반 메서드(비열거형 및 비동기식)에서는 로컬 변수, 메서드 매개변수 또는 인스턴스 필드를 null로 설정하지 않습니다.

(IDisposable.Dispose를 구현하는 경우에도 변수를 null로 설정하면 안 됩니다.)

우리가 고려해야 할 중요한 점은 정적 필드.

정적 필드는 항상 루트 개체입니다., 그래서 그들은 항상 "살아있다"고 여겨진다. 가비지 컬렉터에 의해.정적 필드가 더 이상 필요하지 않은 개체를 참조하는 경우 가비지 수집기가 해당 개체를 수집 가능한 것으로 처리하도록 null로 설정해야 합니다.

전체 프로세스가 종료되는 경우 정적 필드를 null로 설정하는 것은 의미가 없습니다.해당 시점에 모든 루트 개체를 포함하여 전체 힙이 가비지 수집됩니다.

결론:

정적 필드;그게 다야.다른 것은 시간 낭비.

나는 GC 구현자의 설계에 따라 다음과 같이 할 수 없다고 생각합니다. 속도를 올리다 무효화를 포함한 GC.나는 그들이 GC 실행 방법/언제에 대해 걱정하지 않기를 원할 것이라고 확신합니다. 이렇게 유비쿼터스처럼 처리하십시오. 존재 당신을 보호하고 지켜보고 있습니다...(고개를 숙이고 주먹을 하늘로 치켜세웁니다)...

개인적으로 저는 변수 작업을 마친 후 자체 문서화 형식으로 변수를 명시적으로 null로 설정하는 경우가 많습니다.선언하고 사용한 다음 나중에 null로 설정하지 않습니다. 더 이상 필요하지 않은 즉시 null로 설정합니다.나는 분명히 이렇게 말하고 있습니다. "나는 공식적으로 당신과의 관계는 끝났습니다. 떠나세요..."

GC 언어에서 무효화가 필요합니까?아니요.GC에 도움이 되나요?아마도 예, 어쩌면 아니오일 수도 있습니다. 확실하지 않습니다. 설계상으로는 실제로 제어할 수 없으며 이 버전이나 저 버전에 대한 현재 답변에 관계없이 향후 GC 구현에서는 제어할 수 없을 정도로 답변이 변경될 수 있습니다.게다가 널링이 최적화된 경우에는 멋진 것 이상입니다. 논평 당신이 원한다면.

내 발자취를 따르는 다음 불쌍한 바보에게 내 의도가 더 분명해지면 좋겠다고 생각합니다. "할 것 같다" 때때로 GC를 도울 가능성이 있다면 그것은 나에게 그만한 가치가 있습니다.대부분 깔끔하고 명확한 느낌을 주는데 Mongo는 깔끔하고 명확한 느낌을 좋아합니다.:)

나는 그것을 다음과 같이 본다:프로그래밍 언어는 사람들이 다른 사람들에게 의도에 대한 아이디어를 제공하고 컴파일러가 수행할 작업에 대한 작업 요청을 제공할 수 있도록 존재합니다. 컴파일러는 해당 요청을 CPU에 대한 다른 언어(때로는 여러 언어)로 변환합니다. 어떤 언어를 사용했는지, 탭 설정, 설명, 문체 강조, 변수 이름 등을 알려주세요.-- CPU는 어떤 레지스터와 연산 코드, 메모리 위치를 조작할지 알려주는 비트 스트림에 관한 것입니다.코드로 작성된 많은 것들은 우리가 지정한 순서대로 CPU가 소비하는 것으로 변환되지 않습니다.우리의 C, C++, C#, Lisp, Babel, 어셈블러 또는 현실보다는 이론이 무엇이든 작업 명세서로 작성되었습니다.당신이 보는 것은 당신이 얻는 것과 다릅니다. 예, 어셈블러 언어에서도 마찬가지입니다.

나는 "불필요한 것들"(빈 줄처럼)의 사고 방식은 "소음과 혼란스러운 코드"라는 것을 이해합니다. 그것은 내 경력 초기에 나였다.나는 그것을 완전히 이해합니다.이 시점에서 나는 코드를 더 명확하게 만드는 쪽으로 기울었습니다.내 프로그램에 50줄의 "노이즈"를 추가하는 것이 아닙니다. 여기저기서 몇 줄만 추가하는 것입니다.

모든 규칙에는 예외가 있습니다.휘발성 메모리, 정적 메모리, 경쟁 조건, 싱글톤, "부실" 데이터 사용 및 모든 종류의 부패가 있는 시나리오에서는 상황이 다릅니다.메모리는 GC'd Universe의 일부가 아니기 때문에 자신의 메모리를 잠그고 무효화하여 관리해야 합니다. 모두가 이를 이해하기를 바랍니다.GC'd 언어를 사용하는 나머지 시간에는 필요성이나 보장된 성능 향상보다는 스타일의 문제입니다.

결국 GC에 적합한 것과 그렇지 않은 것을 이해했는지 확인하십시오.적절하게 잠그고, 폐기하고, 무효화합니다.왁스 온, 왁스 오프;숨을들이 쉬고 내쉬다;그리고 그 밖의 모든 것에 대해서는 다음과 같이 말합니다.기분이 좋으면 그렇게 하세요.귀하의 마일리지는 다를 수 있습니다.

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top