설명을 할 수 없다는 진술의 중간에 생성 된 idisposable 객체는 어떻게됩니까?

StackOverflow https://stackoverflow.com/questions/415313

문제

SharePoint (다른 객체 모델에도 적용됨)로 작업하고 있다고 말하면서 내 진술의 중간에는 메소드를 호출합니다.이 경우 "OpenWeb ()"를 호출합니다. 이제 spweb 객체에서 dispose ()를 호출 할 수 없습니다. 그렇다면이 누출 기억에 대해 걱정해야합니까?

SPUser spUser = SPControl.GetContextSite(HttpContext.Current).OpenWeb().SiteUsers[@"foo\bar"];

나는 진술을 여러 줄로 나누고 SPWEB 참조를받을 수 있다는 것을 알고 있습니다.

SPWeb spWeb = SPControl.GetContextSite(HttpContext.Current).OpenWeb();
SPUser spUser = spWeb.SiteUsers[@"foo\bar"];
spWeb.Dispose();

내 질문은 미학에 관한 것이 아니라 참조가 없기 때문에 명시 적으로 dispose ()를 호출 할 수없는 idisposable 객체에 어떤 일이 발생하는지에 대한 것입니다.

내가 처음 질문했을 때 충분히 명확하지 않아서 죄송합니다. 이후로 다시 게시했습니다. 지금까지 모든 답변에 감사드립니다.

도움이 되었습니까?

해결책

"명시 적으로 dispose ()을 호출 할 수없는 idisposable 객체는 어떻게됩니까?"

일반적으로 모든 일회용 물체에서 Discoping (암시 적으로 명령문을 사용하거나 명시 적으로)을 호출 할 수 있지만, 가상의 시나리오에서는 할 수 없습니다, 그것 의존합니다 도중에 객체가 구현되었습니다.

일반적으로 .NET 객체는 패턴을 따라갑니다. 이 라인. 패턴은 처분이 호출되지 않은 경우를 치우는 경우 재료를 정리 한 다음 최종화기 억제를 폐기하는 최종화기를 정의하는 것입니다. 메모리 부하가 줄어들고 GC가 작업 할 작업을 줄입니다.

Finalizer에서 Dispose를 호출하는 데있어 많은 문제 중 하나는 단일 스레드 문제를 멀티 스레드 문제로 바꾸고 있다는 것입니다. Finalizer는 다른 버그를 잡기 위해 매우 미묘하고 어려운 몇 가지를 노출시킬 수있는 실. 또한, 예상보다 오래 관리되지 않는 리소스를 유지한다는 것을 의미합니다 (예 : 파일을 열고, 가까이에 전화하거나 처분하는 것을 잊고 다음에 잠긴 경우 열면 잠긴 경우).

결론은 a입니다 모범 사례 모든 일회용 물체를 처분하려면 이상하고 복잡한 버그를 소개 할 수 있습니다. SharePoint와 같은 일부 프레임 워크가 문서에 따라 배치되어서는 안되는 공유 객체 인스턴스를 반환한다는 경고를 통해.

나는 보통 "사용"패턴으로 객체를 처분 할 때 코드가 훨씬 더 읽기 쉬운 것을 발견합니다. 명시 적으로 처분하는 데 따르는 문제는 (Object.Dispose ())입니다. 물체가 할당 된 곳에서 추적하기가 어려울 수 있으며 잊기가 매우 쉽다는 것입니다. 사용 명령문의 곱슬 브래킷을 닫는 것을 잊을 수 없으며, 컴파일러는 불평합니다 :)

편집 / gotcha

에 따르면 MS 문서 getContextSite에 의해 반환되는 공유 지점 공유 개체에 대한 참조에 대한 dispose를 호출해서는 안됩니다. 따라서 여기에서 더 조심해야합니다.

보다 이 답변 안전한 SharePoint 패턴의 경우 사용해야합니다.

그러나 웹 파트의 getContexTSite 메소드가 객체를 제공 할 때와 같은 공유 리소스에 대한 참조가있는 경우 두 메소드를 사용하여 객체를 닫지 마십시오. 공유 리소스에서 두 메소드를 사용하면 액세스 위반 오류가 발생합니다. 공유 리소스를 참조하는 시나리오에서 Windows SharePoint 서비스 또는 포털 응용 프로그램이 객체를 관리하도록하십시오.

다른 팁

다음은 더 관용적이며 더 잘 읽습니다.

using (SPWeb spWeb = SPControl.GetContextSite(HttpContext.Current).OpenWeb())
{
    SPUser spUser = spWeb.SiteUsers[@"foo\bar"];
}

명시 적으로 (또는 암시 적으로, 사용 명세서) 전화 dispose method. 여러 줄에서 코드를 분할 해야하는 또 다른 이유는 다음과 같습니다.

  • 가독성
  • 디버그하는 것이 더 쉽습니다

Dispose 방법은 Finalizer에서 실행될 수 있지만 직접 부르는 것이 더 안전합니다.

선을 나누고 처분을 사용하는 것이 좋습니다. 객체가 idisposable을 구현하는 경우 폐기가 필요하다고 가정하고 사용 블록에서 사용해야합니다.

using (SPWeb spWeb = SPControl.GetContextSite(HttpContext.Current).OpenWeb())
{
    SpUser spUser = null;
    if (spWeb != null)
    {
        spUser = spWeb.SiteUsers[@"foo\bar"];
    }
}

이렇게하면 객체를 처분하고 외부 리소스를 열고있는 OpenWeb () 호출에서 오류를 처리합니다.

메모리 누출? 아니요, 다음 가비지 컬렉션이 정리해야하므로 Idisposable의 구현이 클래스 라이브러리 가이드 라인을 준수한다고 가정하면 걱정해서는 안됩니다.

그러나 코드의 오류가 나타납니다. 귀하가 작업하는 Idisposable의 구현의 수명을 제대로 관리하지 않기 때문에 (이 문제에 대해 자세히 설명합니다. http://www.caspershouse.com/post/a-better-impletation-pattern-for-idisposable.aspx). 두 번째 코드 블록은 좋은 첫 단계이지만 SiteUsers에 대한 호출이 실패한 경우 폐기의 호출을 보장하지는 않습니다.

수정 된 코드는 다음과 같습니다.

// Get the site.
var contextSite = SPControl.GetContextSite(HttpContext.Current);

// Work with the web.
using (SPWeb web = contextSite.OpenWeb())
{
  // Get the user and work with it.
  SPUser spUser = web.SiteUsers[@"foo\bar"];
}

지금까지 어떤 사람들이 말했듯이 : 당신은 당신이 만들지 않는 물체를 처분해서는 안됩니다. 그래서 당신의 예에서 당신은해야합니다 ~ 아니다 spweb 또는 spsite 객체를 처리하십시오!

그것은 현재의 sprequest 객체를 파괴 할 것입니다. 여전히 작동하는 것처럼 보이지만 예를 들어 나중에 새로운 웹 부품을 추가하거나 웹 부품의 도구 창을 열면 모든 종류의 이상한 오류가 발생합니다.

이미 말했듯이, spweb와 spsite의 사례를 처리해야합니다. 당신이 자신을 창조한다 (새로운).

이것은 () 또는 try/finalh (사용하는 () 명령문이 MSIL 코드에 표시되는 방식입니다)를 사용하여 수행 할 수 있습니다. 시도/마지막으로 사용하는 경우 SPWEB/SPSITE 인스턴스에서 NULL을 확인하고 SPWITE가 자동으로 SPWEB를 처리하므로 SPWEB를 먼저 확인하는 것이 가장 좋습니다.

기억해야 할 또 다른 중요한 것은 Allwebs 또는 Webs와 같은 spwebcollection을 반복 할 때 서브 웹을 루프 할 때 서브 웹을 처리하는 것입니다. 서브 웹이 많이 있고 메모리 잠재력이 제한된 32 비트 하드웨어에서 실행중인 경우 Sprequest 객체로 메모리를 매우 빠르게 채울 수 있습니다. 이렇게하면 응용 프로그램 풀이 규칙적으로 재활용되므로 성능이 느려집니다.

그렇다고 말하면 코드 예제에서와 같이 통화를 결합하지 않는 것이 좋습니다. 읽기가 어렵고 만약에 당신은 당신이 처분 해야하는 spweb와 함께 일하고 있었는데, 당신은 할 수 없었습니다! 이런 종류의 메모리 누출은 발견하기가 가장 어렵습니다.

자세한 내용은 Roger Lamb의 블로그를 추천 할 수 있습니다.http://blogs.msdn.com/rogerla또한 Stefan Goßner의 블로그에 대한 기술적 세부 사항 :http://blogs.technet.com/stefan_gossner/archive/2008/12/05/disposing-spweb-and-spsite-objects.aspx

HTH Anders

여기서 많은 대답은 처분이 결국 호출되는 것이 중요하다고 가정합니다. 그러나 Spsite 및 Spweb와 함께 작업 할 때 최대한 빨리 Dispose ()에 전화하고 싶습니다. 결정 언제 당신은 종종 까다로워 야하지만 많은 것이 있습니다 좋은 참조 그 질문에 답할 수 있습니다.

이것이 왜 그런지에 관해서, Stefan Goßner는 훌륭한 요약을 제공합니다. 여기:

각 spweb 및 spsite 객체는 백엔드 SQL 서버와 통신 할 책임이있는 SharePoint COM 객체에 대한 참조를 보유하는 SPREQUEST 객체에 대한 참조를 보유합니다.

SPWEB 객체를 처리하면 실제로 SPWEB 객체를 메모리에서 제거하지 않습니다 (실제로 .NET Framework는 결정 론적으로 메모리에서 객체를 제거 할 수 없습니다). SQL 서버에 연결하고 할당 된 메모리를 해제합니다.

즉, 백엔드 SQL 서버에 대한 연결은 SPWEB 객체가 배치 될 때까지 Sprequest 객체가 생성 된 순간부터 열려 있습니다.

코드 샘플의 모범 사례는 다음과 같습니다.

SPSite contextSite = SPControl.GetContextSite(HttpContext.Current);
using (SPWeb spWeb = contextSite.OpenWeb())
{
  SPUser spUser = spWeb.SiteUsers[@"foo\bar"];
  // Process spUser
}
// DO NOT use spUser
// DO NOT dispose site from HttpContext

SPUSER, SPLIST 등과 같은 SP 객체를 사용하는 것은 안전하지 않습니다. 부모의 SPWEB가 배치 된 후.

에서 http://msdn.microsoft.com/en-us/library/aa973248.aspx 모범 사례 : 일회용 Windows SharePoint 서비스 개체 사용:

SPCONTROL.GETCONTEXTSITE에서 SPSITE 객체를 얻는 경우 호출 응용 프로그램이 객체를 처리하지 않아야합니다. SPWEB 및 SPSITE 객체는 이러한 방식으로 파생 된 내부 목록을 유지하기 때문에 객체를 처리하면 SharePoint 객체 모델이 예기치 않게 행동하게 될 수 있습니다.

아무도 이것을 던져 버린 것 같습니다.

객체에 폐기자가 필요한 경우 (즉, 릴리스 해야하는 리소스를 보유하고 있음), 처분 방법을 호출하는 최종화기를 구현해야합니다.

처리기에서 라인을 추가 할 수 있습니다.

System.GC.SuppressFinalize(this)

폐기자를 호출하면 최종화를 방지합니다. 이렇게하면 NECCESSARY 일 경우 객체를 멋지게 사용할 수 있지만 최종화기를 통해 자체적으로 정리하도록 보장합니다 (C#에 Finalizer가있는 모든 이유).

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