RAM 집중 C # 프로세스가 몇 시간이 지나면 느려짐

c# html-agility-pack memory-management multithreading performance

문제

나는 HTML 페이지를 지속적으로 파싱 할 책임이있는 서버에서 C # 프로세스 (서비스)를 실행한다. HTMLAgilityPack을 사용합니다. 증상은 시간이 지남에 따라 느려지고 느려집니다.

프로세스를 시작할 때 n 페이지 / s를 처리합니다. 몇 시간 후에 속도는 약 n / 2 페이지 / s로 떨어집니다. 며칠 후 n / 10까지 내려갈 수 있습니다. 이 현상은 여러 번 관찰되었으며 다소 결정적입니다. 프로세스가 다시 시작될 때마다 정상적으로 돌아갑니다.

매우 중요한 점은 동일한 프로세스에서 다른 계산을 실행할 수 있으며 속도가 느려지지 않는다는 것입니다. 언제든지 원하는대로 100 % CPU에 도달 할 수 있습니다. 프로세스 자체가 느리지는 않습니다. HTML 구문 분석 만 속도가 느려집니다.

나는 최소한의 코드로 그것을 재현 할 수있다. (실제로 원래의 서비스에서의 행동은 좀 더 극단적이지만 여전히이 코드는 동작을 재현한다.)

public static void Main(string[] args) {
    string url = "https://en.wikipedia.org/wiki/History_of_Texas_A%26M_University";
    string html = new HtmlWeb().Load(url).DocumentNode.OuterHtml;
    while (true) {
        //Processing
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Parallel.For(0, 10000, i => new HtmlDocument().LoadHtml(html));
        sw.Stop();
        //Logging
        using(var writer = File.AppendText("c:\\parsing.log")) {
            string text = DateTime.Now.ToString() + ";" + (int) sw.Elapsed.TotalSeconds;
            writer.WriteLine(text);
            Console.WriteLine(text);
        }
    }
}

이 최소 코드를 사용하면 프로세스가 시작된 후 경과 한 시간 수에 따라 속도 (초당 페이지 수)가 표시됩니다.

여기에 이미지 설명을 입력하십시오.

모든 명백한 원인은 배제되었습니다.

  • HTML 페이지가 더 크거나 다른 경우 (최소 코드에서는 동일한 페이지 임)
  • 전체 RAM : 프로세스가 32GB에서 약 500MB를 사용합니다.
  • 다른 프로세스는 CPU 또는 RAM을 사용합니다.

그것은 RAM과 메모리 할당에 관한 것이 될 수 있습니다. HTMLAgilityPack은 많은 작은 객체 메모리 할당 (HTML 노드와 문자열)을 만든다는 것을 알고 있습니다. 명확한 메모리 할당과 멀티 스레딩은 잘 작동하지 않습니다. 그러나 나는 그 과정이 어떻게 느리고 느리게 될 수 있는지 이해하지 못한다.

일부 RAM 집중 (많은 할당) 처리 속도가 느려지고 느려질 수있는 CLR 또는 Windows에 대해 알고 있습니까? 예를 들어 특정 방식으로 메모리 할당을하는 스레드에 불이익을주는 것과 같은가?

수락 된 답변

HTMLAgilityPack을 사용하여 유사한 동작을 발견했습니다.

나는 한 수익률의 데이터가 컴파일러에서 로컬 변수의 공간 누출을 시작할 때 문제를 일으키는 클래스를 생성한다는 것을 발견했다. 사용할 수있는 코드가 없으므로 ... bla bla, 여기 내 응급 처치 키트입니다.

  1. 올바른 전략 을 세우십시오. app.config에서 GC 수집 상태를 변경하면 조각화에 도움이됩니다.
  2. 필요하지 않을 때 null이 필요한지 확인하십시오. 필요하지 않으면 IEnumerables가 메서드 호출의 호출 메서드와 범위에서 호출되어 메모리를 정리하는 범위를 기다리지 않고 메서드 vaiables의 범위를 훨씬 길게 유지할 수 있습니다. 당신 생각보다! ILSpy에서 코드를 열고 <> d__0 (0) genrated 클래스를 살펴보십시오. d __와 같이 생성 된 것을 볼 수 있습니다. X = X; 이 경우 X는 단편 또는 전체 페이지를 보유 할 수 있습니다.
  3. 로컬 변수는 IEnumable 반복에서 액세스 할 수 없으므로 힙에 배치되지 않습니다.
  4. 잠금이 문제가되기 시작하면 GC를 막기 시작하는 4 세대 램에서 큰 항목이 눈에 띄게됩니다. GC가 스레드를 일시 중지하여 가비지 수집을 수행 할 수 있습니다.
  5. HTMLAgility의 최악의 경우는 조각이 실제 문제가되는 것입니다.

    나는 당신이 HTML 조각의 범위를 고려하기 시작할 때 일이 잘 진행될 것이라고 확신한다. SOS에서 WinDbg를 사용하여 실행을 살펴보고 메모리를 덤프하고 살펴보십시오.

그렇게하는 방법.

  1. WinDebug를 열고 F6을 누른 다음 프로세스에 연결하십시오 (필드에 프로세스 ID를 입력하고 확인을 누르십시오)
  2. 다음을 입력하여 memeory에서 실행을로드하십시오.

    .loadby sos clr

  3. 다음을 입력하십시오

    ! dumpheap -stat

그런 다음 메모리 주소와 크기를 유형별로 그룹화 한 응용 프로그램에 할당 된 메모리 항목을 가져 와서 낮은 헤더에서 높은 헤더로 정렬하면 System.String [] 앞에 무언가가 표시됩니다. 당신이 먼저 조사하고 싶은 고통.

이제 입력 할 수있는 사람을 확인하십시오.

!dumpheap -mt <heap address>

그리고 그 메모리 테이블 (MT)을 사용하는 주소와 그것이 사용하는 램의 크기를 볼 수 있습니다.

이제는 흥미 진진한 것보다 오히려 당신이 입력하는 yode의 x100 라인

!gcroot <address>

출력 할 것은 파일과 메모리를 할당 한 코드 라인이며, 컴파일러는 클래스를 생성하고 그 바이트가 보유한 바이트뿐만 아니라 슬픔을 일으킬 수 있습니다.

이것은 "프로덕션 디버깅"이라고 부를 수 있으며 서버에 액세스 할 수 있으면 작동합니다.

희망이 도움이 되었으면 좋겠다.

월터



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.