티스토리 뷰
목차
C# Sealed 클래스, 성능 향상 최적화 방법 (추상 키워드 예제)
Sealed. Sealed 클래스는 상속되지 않으며, 키워드로 사용한다면 함수 호출 시 성능 향상이 됩니다.
1. 상속되지 않는 특성
2. 특정 상황에서 성능이 향상
이 두 가지 특징을 갖는 키워드라 할 수 있습니다.
Example. sealed 키워드가 적용되면 C# 컴파일러는 당신의 클래스 어셈블리에 "sealed" 메타 데이터를 적용시킵니다. 상위 클래스에선 sealed 키워드가 선언된 클래스를 상속 받을수 없도록 제한합니다. (syntax hint)
Tip: JIT 컴파일러는 sealed 메타 데이터를 이용해 함수 호출을 최적화할 수 있습니다.
The two classes. ITest 인터페이스를 구현하는 두 클래스엔 약간의 차이가 있습니다. GetNumber() 함수(테스트용)가 리턴하는 정수와 TestB 클래스에 추가된 sealed 키워드입니다.
Next: 함수 하나를 갖는 인터페이스(ITest)와 두 개의 클래스가 있습니다. 여기서, 첫번째 클래스인 TestA는 sealed 클래스가 아니지만, 두번째 클래스인 TestB는 sealed 클래스입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | using System; /// <summary> /// Example interface. /// </summary> interface ITest { /// <summary> /// Method required by the interface. /// </summary> int GetNumber(); } /// <summary> /// Non-sealed class that implements an interface. /// </summary> class TestA : ITest { /// <summary> /// Interface implementation. /// </summary> public int GetNumber() { return 1; } } /// <summary> /// Sealed class that implements an interface. /// </summary> sealed class TestB : ITest { /// <summary> /// Interface implementation. /// </summary> public int GetNumber() { return 2; } } class Program { static void Main() { ITest test1 = new TestA(); // Regular class ITest test2 = new TestB(); // Sealed instantiation Console.WriteLine(test1.GetNumber()); // TestA.GetNumber Console.WriteLine(test2.GetNumber()); // TestB.GetNumber } } | cs |
Output
1
2
Discussion. .NET 프레임워크가 인터페이스 함수와 가상 함수를 호출할 때, 어떤 메커니즘의 차이가 있을까요? 클래스의 다형성(polymorphism)을 지원하기 위해 프로그램 언어는 가상의 디스패치 테이블이 담긴 함수를 생성합니다.
Then. 이후 런타임 시점에 이 함수를 찾는데, .NET 프레임워크에는 각 타입별 포인터를 보유하게 됩니다. (.NET 프레임워크에서 관리하는 영역을 managed heap) 포인터들은 가상 함수 디스패치에 사용됩니다.
Also, JIT(just-in-time) 최적화 기능은 실행 환경에 따라 수행되지 않을 수도 있습니다. 비주얼 스튜디오로 프로그램을 실행하면 sealed는 최적화되지 않습니다.
However. 다른 디버거를 이용해 외부에서 프로그램을 실행하면 최적화가 됩니다.
JIT 최적화 및 디버깅 : https://msdn.microsoft.com/ko-kr/library/ms241594.aspx
모듈을 로드할 때 JIT 최적화 기능 사용 안 함 옵션을 해제하면 최적화된 JIT 코드를 디버깅할 수 있지만 최적화된 코드와 소스 코드 사이의 불일치로 인해 디버깅 기능이 제한될 수도 있습니다.
Benckmark. sealed 키워드를 이용하면 성능 향상이 됩니다. 아래 벤치마킹 결과에 따르면 인터페이스 함수를 상속받는 두 클래스 중 sealed로 선언된 클래스의 속도가 약 1/3 가량 빨랐습니다.
Tip. 인터페이스가 많은 프로그램일수록 sealed를 사용하면 함수 호출 속도를 향상할 수 있습니다.
Outer variables used in benchmark
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | int sum1 = 0; int sum2 = 0; ITest test1 = new TestA(); ITest test2 = new TestB(); Contents of tight loops sum1 += test1.GetNumber(); // Loop 1 body sum1 += test1.GetNumber(); sum1 += test1.GetNumber(); sum1 += test1.GetNumber(); sum1 += test1.GetNumber(); sum2 += test2.GetNumber(); // Loop 2 body sum2 += test2.GetNumber(); sum2 += test2.GetNumber(); sum2 += test2.GetNumber(); sum2 += test2.GetNumber(); | cs |
Results
Iterations: 1000000 * 100
TestA.GetNumber (regular): 2.490 ns
TestB.GetNumber (sealed): 2.162 ns [faster]
In this benchmark. 똑같이 다섯번의 함수 호출이 이뤄집니다. 이를 고려하여 누적된 결과는 5로 나누어 나노초로 변환했습니다.
Summary. 위에서 C#의 sealed 키워드를 살펴봤습니다. 함수 호출 시간 단축에 유용한 이 키워드를 클래스에 적용하여 성능 향상을 확인해 봤습니다. sealed는 성능상의 이점이 있지만, 프로그램 실행 환경에 따라 결과는 다를 수 있습니다.
C# Sealed 클래스, 성능 향상 최적화 방법 (추상 키워드 예제)