. NET 4.6에서 GC.TryStartNoGCRegion ~ GC.EndNoGCRegion 라는 것이 추가 되었다.

GC.TryStartNoGCRegion에서 GC.EndNoGCRegion까지 자동 GC를 억제할 수 있다.

 

 

처리 중 GC가 일어날 경우

아래 코드는 1MB의 바이트 배열을 생성하고 GC 회수 대상이 될 수 있는 구성이다.

using System;

using System.Runtime;

using System.Threading;

 

namespace TestSpace {

    class Program {

        static void Main( string[] args ) {

            for( int i = 0; i < 30; i++ ) {

                var n = create();

                Thread.Sleep( 100 );

                GC.KeepAlive( n );

 

                Console.WriteLine( $"GC:{GC.CollectionCount( 0 ) } {GC.GetTotalMemory( false ):#,##byte} " );

            }

            Console.ReadLine();

 

        }

 

        public static WeakReference<byte[]> create() {

            var weak = new WeakReference<byte[]>( new byte[1048576] );

            return weak;

        }

 

    }

}

 

동작 환경에 따라서 차이가 있겠지만 몇 번 GC가 발생하는지 확인할 수 있다.

 

 

GC.TryStartNoGCRegion ~ GC.EndNoGCRegion 로 둘러싸 본다

속도가 중시되는 경우 GC 발생이 병목이 될 수 가능성이 있다.

 

GC.TryStartNoGCRegion에 메모리 사이즈(바이트 단위)를 지정한다.

이곳에서 지정한 사이즈가 소비될 때까지 GC가 억제되게 된다.

 

예를 들어 GC.TryStartNoGCRegion(15728640)라고 지정하면 15MB 소비할 때까지 GC를 억제하게 된다.

또한 지정 가능한 최대 크기는 실행 환경에 의해서 결정된다.

상세는 Fundamentals of Garbage Collection을 참조.

https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx

 

일반적인 클라이언트 PC 32비트 환경에서는 16MB, 64비트 환경에서는 256MB 이다.

아래의 예는 32비트 환경을 예상한 것이다.

using System;

using System.Runtime;

using System.Threading;

 

namespace TestSpace {

    class Program {

        static void Main( string[] args ) {

 

            if( GC.TryStartNoGCRegion( 15728640 ) ) {

                for( int i = 0; i < 30; i++ ) {

                    var n = create();

                    Thread.Sleep( 100 );

                    GC.KeepAlive( n );

 

                    Console.WriteLine( $"GC:{GC.CollectionCount( 0 ) } {GC.GetTotalMemory( false ):#,##byte} " );

                }

 

                if( GCSettings.LatencyMode == GCLatencyMode.NoGCRegion )

                    GC.EndNoGCRegion();

            }

            Console.ReadLine();

 

        }

 

        public static WeakReference<byte[]> create() {

            var weak = new WeakReference<byte[]>( new byte[1048576] );

            return weak;

        }

 

    }

 

}

 

GC.TryStartNoGCRegion 에서 지정한 15MB까지 GC가 이뤄지지 않는 것을 확인할 수 있다.

그러나 15MB를 초과 한 시점에서 자동적으로 GC가 발동 하는 것도 확인할 수 있다.

 

 

주의 사항

GC.TryStartNoGCRegion을 호출해서 새롭게 할당된 메모리가 지정 크기까지 도달할 때까지 GC를 억제하는 것이다.

이미 할당된 메모리 사이즈는 무의미하다.

 

GC.TryStartNoGCRegion을 다중으로 호출 할 수는 없다.

GC.TryStartNoGCRegion에 성공하면 GCSettings.LatencyMode값이 GCLatencyMode.NoGCRegion로 변경된다.

거꾸로 말하면, GCSettings.LatencyMode == GCLatencyMode.NoGCRegion 이라면 GC 억제 중이라고 판단할 수 있다.

 

GC.EndNoGCRegion() GCSettings.LatencyMode GCLatencyMode.NoGCRegion인 경우에만 실행 가능하다.

GC.EndNoGCRegion()를 호출하지 않아도 자동으로 해제되는 경우가 있다.

GC.TryStartNoGCRegion에서 지정한 사이즈에 달했다

GC.Collect등이 호출 되어 수동에 의한 GC가 발생했다

GC.GetTotalMemory(true)가 실행되었다

 

이런 경우 그 시점에서 GC의 억제 상태가 해제된다.

 

 

MSDN: GC.TryStartNoGCRegion

https://msdn.microsoft.com/en-us/library/system.gc.trystartnogcregion(v=vs.110).aspx

 

동시에 복수의 GC.TryStartNoGCRegion을 호출한 경우 InvalidOperationException이 발생하므로, 멀티 쓰레드에서 GC.TryStartNoGCRegion~GC.EndNoGCRegion을 할 때는 반드시 동기화 해야 한다.

 

출처: http://qiita.com/Temarin_PITA/items/749ad661fd13d7402794

 

저작자 표시
신고
by 흥배 2016.08.01 08:00