실시간 .NET 애플리케이션에서 가비지 수집을 방지하는 방법은 무엇입니까?

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

문제

저는 네트워크에서 메시지를 수신하고 이를 메시지 유형에 따라 다른 개체로 변환한 후 마지막으로 해당 메시지에 애플리케이션 비즈니스 로직을 적용하는 금융 C# 애플리케이션을 작성하고 있습니다.

요점은 비즈니스 로직이 적용된 후에는 이 인스턴스가 다시는 필요하지 않을 것이라고 확신한다는 것입니다.가비지 수집기가 해당 항목을 해제할 때까지 기다리는 대신 명시적으로 '삭제'하고 싶습니다.

C#에서 더 좋은 방법이 있습니까? 개체 풀을 사용하여 항상 동일한 인스턴스 집합을 재사용해야 합니까, 아니면 더 나은 전략이 있습니까?

목표는 시간이 중요한 프로세스 중에 CPU를 사용하기 위해 가비지 수집을 방지하는 것입니다.

도움이 되었습니까?

해결책

즉시 삭제하지 마십시오.각 개체에 대해 가비지 수집기를 호출하는 것은 나쁜 생각입니다.일반적으로 당신은 정말 가비지 수집기를 전혀 망치고 싶지 않으며 시간이 중요한 프로세스라도 민감한 경우 발생하기를 기다리는 경쟁 조건일 뿐입니다.

그러나 앱이 바쁜 기간과 가벼운 로드 기간이 있다는 것을 알고 있다면 다음 바쁜 기간 전에 정리를 장려하기 위해 가벼운 기간에 도달할 때 보다 일반적인 GC.Collect()를 시도할 수 있습니다.

다른 팁

이봐: http://msdn.microsoft.com/en-us/library/bb384202.aspx

현재 중요한 일을 하고 있다고 가비지 컬렉터에게 말하면 가비지 컬렉터는 여러분에게 친절하게 대할 것입니다.

당신은 스스로 공격합니다. 객체 풀을 사용하고 해당 객체를 재사용하십시오.해당 객체에 대한 호출의 의미는 팩토리 외관 뒤에 숨겨야 합니다.미리 정의된 방식으로 풀을 확장해야 합니다.아마도 한계(고수 알고리즘 또는 고정 비율)에 도달할 때마다 크기가 두 배로 늘어날 수 있습니다.GC.Collect()를 호출하지 말 것을 강력히 권합니다.

풀의 로드가 충분히 낮아지면 풀을 축소할 수 있으며 이로 인해 결국 가비지 수집이 실행됩니다. 이에 대해 CLR이 걱정하도록 하세요.

가비지 수집기를 추측하는 것은 일반적으로 매우 나쁜 생각입니다.Windows에서 가비지 수집기는 다음과 같습니다. 세대적인 것 꽤 효율적이라고 믿을 수 있습니다.이 일반 규칙에는 몇 가지 주목할만한 예외가 있습니다. 가장 일반적인 것은 일회성 이벤트가 발생하여 많은 오래된 개체가 죽는다는 사실입니다. 일단 개체가 Gen2(가장 오래 지속됨)로 승격되면 그들은 주변에 머무르는 경향이 있습니다.

언급한 경우에는 수명이 짧은 여러 개체를 생성하는 것처럼 들립니다. 이로 인해 Gen0 컬렉션이 생성됩니다.어쨌든 이런 일은 상대적으로 자주 발생하며 가장 효율적입니다.원하는 경우 재사용 가능한 개체 풀을 사용하여 이를 방지할 수 있지만, 그러한 조치를 취하기 전에 GC가 성능 문제인지 확실히 확인하는 것이 가장 좋습니다. CLR 프로파일러는 이를 수행하기 위한 도구입니다.

가비지 수집기는 다양한 .NET 프레임워크에서 다릅니다. 컴팩트 프레임워크(Xbox 360 및 모바일 플랫폼에서 실행됨)에서는 비세대 GC이므로 무엇에 대해 훨씬 더 주의해야 합니다. 프로그램이 생성하는 쓰레기.

GC.Collect()를 강제하는 것은 일반적으로 나쁜 생각입니다. GC가 최선의 작업을 수행하도록 두십시오.필요한 경우 성장할 수 있는 개체 풀을 사용하는 것이 가장 좋은 솔루션인 것 같습니다. 저는 이 패턴을 성공적으로 사용했습니다.

이렇게 하면 가비지 수집뿐만 아니라 정기적인 할당 비용도 피할 수 있습니다.

마지막으로 GC가 문제를 일으키는 것이 확실합니까?성능 절약 솔루션을 구현하기 전에 이를 측정하고 증명해야 합니다. 불필요한 작업이 발생할 수 있습니다!

"목표는 시간이 중요한 프로세스 중에 CPU를 사용하기 위해 가비지 수집을 피하는 것입니다."

큐: 시간이 중요하다는 것은 하드웨어의 난해한 부분을 듣고 있고 인터럽트를 놓칠 여유가 없다는 뜻입니까?

ㅏ: 그렇다면 C#은 사용할 언어가 아니며 이를 위해서는 Assembler, C 또는 C++가 필요합니다.

큐: 시간이 매우 중요하다면 파이프에 많은 메시지가 있고 가비지 수집기로 인해 속도가 느려지는 것을 원하지 않는다는 의미입니까?

ㅏ: 그렇다면 쓸데없는 걱정을 하고 있는 것입니다.개체의 수명이 매우 짧다는 것은 가비지 수집기가 성능 저하 없이 개체를 매우 효율적으로 재활용한다는 의미입니다.

그러나 확실하게 알 수 있는 유일한 방법은 테스트하는 것입니다. 지속적인 테스트 메시지 스트림을 밤새 처리하도록 설정하는 것입니다. GC가 시작될 때 성능 통계를 발견할 수 있다면 놀랄 것입니다. 그것을 발견하면 그것이 실제로 중요하다면 더욱 놀랄 것입니다).

Garbage Collector의 작동 방식을 잘 이해하고 느끼면 여기서 생각하는 것이 권장되지 않는 이유를 이해하게 될 것입니다.CLR이 메모리에서 개체를 재배열하는 데 시간을 소비하는 것을 정말로 좋아하지 않는 한 많이.

앱이 얼마나 집약적인가요?나는 3개의 사운드 카드(Managed DirectX, 44.1KHz, 스테레오, 16비트)를 8KB 블록으로 캡처하고 3개의 스트림 중 2개를 TCP/IP를 통해 다른 컴퓨터로 보내는 앱을 작성했습니다.UI는 3개 채널 각각에 대해 오디오 레벨 미터와 (부드러운) 스크롤 제목/아티스트를 렌더링합니다.이는 XP, 1.8GHz, 512MB 등이 설치된 PC에서 실행됩니다.이 앱은 CPU의 약 5%를 사용합니다.

나는 GC 메소드를 수동으로 호출하는 것을 피했습니다.하지만 낭비적인 몇 가지 사항을 조정해야 했습니다.나는 낭비적인 부분을 다듬기 위해 RedGate의 Ant 프로파일러를 사용했습니다.멋진 도구입니다!

사전 할당된 바이트 배열 풀을 사용하고 싶었지만 관리되는 DX 어셈블리가 바이트 버퍼를 내부적으로 할당한 다음 이를 앱에 반환합니다.그럴 필요가 없다는 것이 밝혀졌습니다.

시간이 절대적으로 중요한 경우 C/C++와 같은 결정적 플랫폼을 사용해야 합니다.GC.Collect()를 호출해도 CPU 주기가 생성됩니다.

귀하의 질문은 메모리를 절약하고 객체를 제거하겠다는 제안으로 시작됩니다.이는 공간이 중요한 최적화입니다.GC는 인간보다 이 상황을 더 잘 최적화하므로 실제로 원하는 것이 무엇인지 결정해야 합니다.

들어보면 C#에는 없는 결정론적 마무리(C++의 소멸자)에 대해 이야기하는 것 같습니다.C#에서 찾을 수 있는 가장 가까운 것은 일회용 패턴입니다.기본적으로 IDisposable 상호 작용.

기본 패턴은 이렇습니다.

public class MyClass: IDisposable
{
    private bool _disposed;

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }

    protected virtual void Dispose( bool disposing )
    {
        if( _disposed )    
            return;

        if( disposing )
        {
            // Dispose managed resources here
        }

        _disposed = true;
    }
}

풀에 있는 각 유형의 인스턴스 수를 제한하고 이미 완료된 인스턴스를 재사용할 수 있습니다.풀의 크기는 처리할 메시지의 양에 따라 달라집니다.

메시지를 받을 때마다 개체의 새 인스턴스를 생성하는 대신 이미 사용된 개체를 재사용하는 것은 어떨까요?이렇게 하면 가비지 수집기와 싸우지 않고 힙 메모리가 조각화되지 않습니다.**

각 메시지 유형에 대해 사용되지 않는 인스턴스를 보관할 풀을 생성할 수 있습니다.네트워크 메시지를 받을 때마다 메시지 유형을 확인하고 해당 풀에서 대기 중인 인스턴스를 꺼내 비즈니스 논리를 적용합니다.그런 다음 해당 메시지 개체 인스턴스를 다시 풀에 넣습니다.

코드를 쉽게 확장할 수 있도록 인스턴스로 풀을 "지연 로드"하는 것이 좋습니다.따라서 풀 클래스는 null 인스턴스가 당겨진 시기를 감지하고 이를 전달하기 전에 채워야 합니다.그런 다음 호출 코드가 이를 풀에 다시 넣으면 실제 인스턴스가 됩니다.

** "개체 풀링은 개체를 할당 및 할당 해제하는 대신 재사용할 수 있도록 하는 패턴으로, 힙 조각화와 비용이 많이 드는 GC 압축을 방지하는 데 도움이 됩니다."

http://geekswithblogs.net/robp/archive/2008/08/07/speedy-c-part-2-optimizing-memory-allocations---pooling-and.aspx

이론적으로 CPU에 과부하가 걸리거나 꼭 필요한 경우가 아니면 GC가 실행되어서는 안 됩니다.그러나 필요한 경우 모든 개체를 메모리(아마도 싱글톤 인스턴스)에 유지하고 준비가 되지 않은 경우 정리하지 않는 것이 좋습니다.이것이 아마도 GC 실행 시기를 보장하는 유일한 방법일 것입니다.

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