2010-04-29 4 views
14

최근에 WinForms 앱에서 .NET "메모리 누수"(예기치 않은 느린 GC 루팅 된 객체)를 조사했습니다. 거대한 보고서를로드하고 닫은 후에도 gen2 모음을 몇 개 사용한 후에도 메모리 사용량이 예상대로 감소하지 않았습니다. 누락 된 이벤트 처리기로보고 컨트롤을 유지한다고 가정 할 때 열린 WinDbg를 열어서 어떤 일이 발생했는지 알 수있었습니다..NET RegEx "메모리 누수"조사

!dumpheap -stat 명령은 문자열 인스턴스에서 많은 양의 메모리를 사용한다고보고했습니다. 더 나아가 이것을 !dumpheap -type System.String 명령으로 수정하면 보고서에 사용 된 90MB 문자열 인 주소 03be7930이 발견되었습니다. 마지막 단계는 !gcroot 03be7930을 호출하여 어떤 객체가 활성 상태로 유지되는지 확인하는 것입니다.

내 기대치가 잘못되었습니다.보고 컨트롤 (및 보고서 문자열)에 걸려있는 unhooked 이벤트 처리기가 아니었지만 대신 System.Text.RegularExpressions.CachedCodeEntry의 자손 인 System.Text.RegularExpressions.RegexInterpreter 인스턴스가 보유하고있었습니다. 지금, Regex의 캐싱은 (다소) 일반적인 지식으로 Regex를 사용할 때마다 재 컴파일해야하는 오버 헤드를 줄이는 데 도움이됩니다. 그러나 이것이 내 문자열을 살아있게 유지하는 것과 무슨 상관이 있습니까?

Reflector를 사용하여 분석 한 결과 Regex 메서드가 호출 될 때마다 입력 문자열이 RegexInterpreter에 저장되는 것으로 나타났습니다. RegexInterpreter는 후속 Regex 메서드 호출을 통해 새 문자열이 입력 될 때까지이 문자열 참조를 유지합니다. Regex.Match 인스턴스 및 다른 인스턴스에 매달아 비슷한 동작을 기대합니다.

  • Regex.Split, Regex.Match, Regex.Replace 등
    • Regex.Run
      • RegexScanner.Scan (RegexScanner는 기본 클래스, RegexInterpreter : 체인이 같은 것입니다 위에서 설명한 서브 클래스입니다).

      정규식은보고를 위해 사용되는 잘못된

는 거의 사용되지 않는, 따라서 가능성이 기존의 보고서 문자열을 지우고 다시 사용할 수 있습니다. Regex가 나중에 사용 되더라도 다른 대형 보고서를 처리 할 수 ​​있습니다. 이것은 상대적으로 중요한 문제이며 단지 평이한 느낌이 듭니다.

모두 나는이 시나리오를 해결하는 방법 또는 최소한이 시나리오를 해결하는 방법에 대한 몇 가지 옵션을 발견했습니다. 나는 지역 사회가 먼저 반응하도록 할 것이고, 아무도 찾는 사람이 앞으로 나오지 않으면 나는 하루나 이틀 안에 어떤 격차라도 메울 것이다.

+1

Regex를 만들 때'Compiled' 옵션을 사용하고 있습니까? –

+0

아니요,이 경우 '컴파일 된'옵션이 사용되지 않았습니다. –

답변

8

Regex의 인스턴스 또는 문자열 패턴을 사용하는 정적 Regex 메서드를 사용하고 있습니까? According to this post, Regex 인스턴스는 캐싱에 참여하지 않습니다.

+2

예, 정적 Regex 방법의 사용이 범인이었습니다.Reflector를 통해 정적 메서드에서 캐싱을 사용하는지 확인할 수 있습니다. 모든 정적 호출은 'useCache'매개 변수를 사용하는 개인 ctor를 사용하여 Regex를 만듭니다. 여기 간단한 해결책은 정적 방법을 사용하지 않는 것입니다. 거대한 입력 문자열을 처리하는 것보다 컴파일이 간단하기 때문에 캐싱은 중요하지 않습니다. Regex를 사용하는 방법에 따라 유용 할 수있는 다른 솔루션은 Regex.CacheSize를 0으로 설정하거나 Regex를 통해 빈 문자열을 실행하여 Regex 캐싱을 사용하지 않도록 설정하는 것입니다. –

0

컴파일 된 Regex 인스턴스화로 전환하는 것이 더 오래 걸리지 만이 이상한 누출의 영향을받지 않을 수도 있습니다.

자세한 내용은 http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regexoptions%28v=VS.100%29.aspx을 참조하십시오.

또는 Regex 인스턴스를 필요 이상으로 길게 잡지 마십시오. 각 보고서 호출에 대해 새로 작성해야합니다.

+2

Downvoted, [정규식 컴파일시 항상 누출 메모리가 있기 때문에] (http://blog.codinghorror.com/to-compile-or-not-to-compile/), 전체적으로 언로드 할 수없는 어셈블리는 언로드 할 수 없으므로 AppDomain) :'언급해야 할 컴파일 작업에 더 많은 비용이 소요됩니다. Reflection.Emit을 사용하여 일리노이를 방출하면 많은 코드가로드되고 많은 메모리가 사용됩니다. 다시는 잊지 못할 추억이 아닙니다. "완전히 새로운 도전을 불러 일으키는 AppDomain을 쓰지 않는 한 예를 들어 AppDomain의 성능과 비교하여 AppDomain의 성능이 좋지 않은 경우와 같습니다. –