문제

나의 많은 걸쳐 올 최적화 팁는 말을 표시해야 합니다 당신의 클래스로 밀봉성하는 성능 혜택을 누릴 수 있습니다.

나는 일부를 확인하는 테스트는 성과 차이와 발견한 없음.내가 뭔가 잘못하고 있는가?나는 경우 밀봉되는 클래스는 더 나은 결과를 제공?

누군가 테스트를 실행하고 보는 차이가 있나요?

도록 도와주세요:)

도움이 되었습니까?

해결책

지터가 때때로 사용 비상 전화하는 방법에서 밀봉한 수업 방법이 없으므로 그들은 확장 할 수 있습니다.

가 있는 복잡한 규칙에 대한 호출의 유형,가상/비가상,그리고 내가 알지 못하는 그들을 모두 할 수 있도록 개요 정말 당신을 위해 그들을,하지만 당신을 위해 밀봉되는 클래스 및 가상 방법을 찾을 수 있습니다 몇 가지 기사에서 주제입니다.

참고하는 모든 종류의 성능 이점을 얻을 것이다 이 수준에서 최적화의로 간주되어야 마지막-리조트,항상 최적화 알고리즘 레벨 전에 당신은에서 최적화하여 코드 수준이다.

여기에는 하나의 링크는 언급 this: 산책에서 밀봉한 키워드

다른 팁

대답은 없는 밀봉된 클래스지 않을 수행보다 더 나은 비 밀봉된다.

문제를 내려 오 callcallvirt IL op 코드입니다. Call 보다 빠르 callvirt, 고 callvirt 는 주로 사용되는 경우 당신은 알지 못하는 경우 개발 하위.그래서 사람들이 생각하는 경우 밀봉 등 모든 op 코드에서 변경됩 calvirts 하기 calls 고 빠를 것이다.

불행하게도 callvirt 가 다른 것에 유용하게도,검사와 같은 null 참조가 있습니다.즉,이 경우에도 클래스 밀봉,참조될 수 있습 null 이 아니고서 callvirt 이 필요합니다.당신이 주변에 얻을 수 있는 이(필요 없이 밀봉 등),그러나 그것은 무의미합니다.

구조체 사용 call 할 수 없기 때문에 하위 클래스고 있지 않은 null 입니다.

이 질문에 대한 더 많은 정보:

전화 callvirt

업데이트:로습니다.NET Core2.0.NET 데스크탑 4.7.1,CLR 지원 devirtualization.이 걸릴 수 있는 방법에는 밀폐 클래스고 대체 가상 통화를 직접적인 통화를 할 수 있습 또한 이것을 위한 비 밀봉된 클래스의 경우 파악할 수 있는 것이 안전합니다.

이러한 경우(밀폐하는 클래스 CLR 수 없었다 그렇지 않으면 감지로 안전하 devirtualise),밀봉된 클래스는 실제로 제공 몇 가지 종류의 성능도 향상됩니다.

는 말했다,나는 생각하지 않을 것에 대해 걱정 가치가 당신은 이미 프로파일 된 코드고 결정하는 당신에 특히 뜨거운 경로 호출되는 수백만의 시간 또는 무언가 다음과 같다:

https://blogs.msdn.microsoft.com/dotnet/2017/06/29/performance-improvements-in-ryujit-in-net-core-and-net-framework/


원래는 대답한다:

나는 다음과 같은 테스트 프로그램,디컴파일된 다음 그것을 사용하는 반사체 무엇을 보 MSIL 코드가 방출됩니다.

public class NormalClass {
    public void WriteIt(string x) {
        Console.WriteLine("NormalClass");
        Console.WriteLine(x);
    }
}

public sealed class SealedClass {
    public void WriteIt(string x) {
        Console.WriteLine("SealedClass");
        Console.WriteLine(x);
    }
}

public static void CallNormal() {
    var n = new NormalClass();
    n.WriteIt("a string");
}

public static void CallSealed() {
    var n = new SealedClass();
    n.WriteIt("a string");
}

모든 경우에서,C#컴파일러(Visual studio2010 년에 출시를 구축 구성)방출한 동일한 MSIL 는 다음과 같습니다:

L_0000: newobj instance void <NormalClass or SealedClass>::.ctor()
L_0005: stloc.0 
L_0006: ldloc.0 
L_0007: ldstr "a string"
L_000c: callvirt instance void <NormalClass or SealedClass>::WriteIt(string)
L_0011: ret 

자주 인용하는 이유는 사람들이 말하는 밀봉 성능을 제공합 혜택을 컴파일러 알고 있는 클래스지 않는 무시할 수 있습니다,따라서 사용 callcallvirt 지 않기 때문이 있을 확인에 대한 가상 꾸러미,etc.으로 입증하는,위의 사실이 아닙니다.

내 생각에도 불구 MSIL 은 동일한,아마도 JIT 컴파일러는 밀봉된 클래스가 다른가?

I ran 릴리스에서 구축 visual studio 디버거와 볼 디 컴파일 86 출력됩니다.두 경우 모두에서,86 코드를 동일 제외하고,클래스 이름과 기능 메모리 주소를(는 물론야 합니다).여기에 그것이

//            var n = new NormalClass();
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  sub         esp,8 
00000006  cmp         dword ptr ds:[00585314h],0 
0000000d  je          00000014 
0000000f  call        70032C33 
00000014  xor         edx,edx 
00000016  mov         dword ptr [ebp-4],edx 
00000019  mov         ecx,588230h 
0000001e  call        FFEEEBC0 
00000023  mov         dword ptr [ebp-8],eax 
00000026  mov         ecx,dword ptr [ebp-8] 
00000029  call        dword ptr ds:[00588260h] 
0000002f  mov         eax,dword ptr [ebp-8] 
00000032  mov         dword ptr [ebp-4],eax 
//            n.WriteIt("a string");
00000035  mov         edx,dword ptr ds:[033220DCh] 
0000003b  mov         ecx,dword ptr [ebp-4] 
0000003e  cmp         dword ptr [ecx],ecx 
00000040  call        dword ptr ds:[0058827Ch] 
//        }
00000046  nop 
00000047  mov         esp,ebp 
00000049  pop         ebp 
0000004a  ret 

그때 생각했어 실행하는 디버거에서 원인을 수행하는 더 적은 공격적인 최적화?

나는 다음 달 독립 릴리즈를 구축 실행 밖의 모든 디버깅 환경 및 사 WinDBG+SOS 침입 후 프로그램을 완료했다고 볼 dissasembly 의 JIT 컴파일 86 코드입니다.

당신이 볼 수 있듯이에서 아래 코드는,외부에서 실행되는 경우 디버거 JIT 컴파일러 더 공격적이며,인라인 이 WriteIt 방법으로 디자인을 자랑합니다.중요한 것은 그러나 그것이 동일한 호출하는 경우 밀봉 vs 비 밀봉된 클래스입니다.없는 차이가 무엇이든지 간에는 밀폐형 또는 nonsealed 클래스입니다.

여기에서 그것은 때 호출하면 정상적인 클래스:

Normal JIT generated code
Begin 003c00b0, size 39
003c00b0 55              push    ebp
003c00b1 8bec            mov     ebp,esp
003c00b3 b994391800      mov     ecx,183994h (MT: ScratchConsoleApplicationFX4.NormalClass)
003c00b8 e8631fdbff      call    00172020 (JitHelp: CORINFO_HELP_NEWSFAST)
003c00bd e80e70106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c00c2 8bc8            mov     ecx,eax
003c00c4 8b1530203003    mov     edx,dword ptr ds:[3302030h] ("NormalClass")
003c00ca 8b01            mov     eax,dword ptr [ecx]
003c00cc 8b403c          mov     eax,dword ptr [eax+3Ch]
003c00cf ff5010          call    dword ptr [eax+10h]
003c00d2 e8f96f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c00d7 8bc8            mov     ecx,eax
003c00d9 8b1534203003    mov     edx,dword ptr ds:[3302034h] ("a string")
003c00df 8b01            mov     eax,dword ptr [ecx]
003c00e1 8b403c          mov     eax,dword ptr [eax+3Ch]
003c00e4 ff5010          call    dword ptr [eax+10h]
003c00e7 5d              pop     ebp
003c00e8 c3              ret

대 밀폐 클래스:

Normal JIT generated code
Begin 003c0100, size 39
003c0100 55              push    ebp
003c0101 8bec            mov     ebp,esp
003c0103 b90c3a1800      mov     ecx,183A0Ch (MT: ScratchConsoleApplicationFX4.SealedClass)
003c0108 e8131fdbff      call    00172020 (JitHelp: CORINFO_HELP_NEWSFAST)
003c010d e8be6f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c0112 8bc8            mov     ecx,eax
003c0114 8b1538203003    mov     edx,dword ptr ds:[3302038h] ("SealedClass")
003c011a 8b01            mov     eax,dword ptr [ecx]
003c011c 8b403c          mov     eax,dword ptr [eax+3Ch]
003c011f ff5010          call    dword ptr [eax+10h]
003c0122 e8a96f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)
003c0127 8bc8            mov     ecx,eax
003c0129 8b1534203003    mov     edx,dword ptr ds:[3302034h] ("a string")
003c012f 8b01            mov     eax,dword ptr [ecx]
003c0131 8b403c          mov     eax,dword ptr [eax+3Ch]
003c0134 ff5010          call    dword ptr [eax+10h]
003c0137 5d              pop     ebp
003c0138 c3              ret

나에게 이 제공하는 단단한 증거가 있다는 할 수 없 어떤 성능 개선 사이에서 메서드를 호출하는 밀봉 vs 비상...내 생각에 나는 행복제:-)

으로 나가 알고 있다는 보장이 없습의 성능도 향상됩니다.하지만 거기에 수있는 기회를 줄이 성능에 따라 특정 조건 밀봉된 방법입니다.(밀봉된 등 모든 방법을 밀봉한다.)

하지만 그것을 컴파일러 구현 및 실행은 환경입니다.


상세정보

많은 현대인의 Cpu 를 사용하여 긴 파이프라인 구조로 성능을 향상시킬 수 있습니다.기 때문에 CPU 는 매우 보다 더 빠른 메모리,CPU 가 프리패치 코드 메모리에서 가속하는 파이프라인.가 아닌 경우에는 코드를 준비에 적절한 시간,파이프라인이 될 것입니다.

이 큰 장애물이라고 동적 dispatch 중단시키는 이것은'미리'최적화입니다.을 이해할 수 있으로 조건부 분기.

// Value of `v` is unknown,
// and can be resolved only at runtime.
// CPU cannot know which code to prefetch.
// Therefore, just prefetch any one of a() or b().
// This is *speculative execution*.
int v = random();
if (v==1) a();
else b();

CPU 를 프리패치할 수 없음 코드를 실행하므로 이러한 상황에서는 다음 코드의 위치는 알 수 없는 상태까지는 해결되었습니다.그래서 이 위험 원인 파이프라인 유휴 상태입니다.고 성능 저하로 유휴 상태에서 거대한 정기적입니다.

비슷한 일이 일어날의 경우에는 방법이 공지사항을 참고하시기 바랍니다.컴파일러 결정할 수 있는 적절한 재정의하는 방법에 대한 현재 메소드를 호출하지만,때때로 그것이 불가능합니다.이 경우,적절한 방법에만 확인할 수 있습니다.이 경우도의 동적 파견하고,메인 이유로의 동적으로 입력한 언어를 일반적으로 느린 보다 정적으로 입력한 언어입니다.

일부의 CPU(를 포함하여 최근 Intel x86 칩)기술을 사용하라 투기 실행 을 활용하는 파이프라인에서도 상황이다.그냥 프리패치의 실행 경로입니다.하지만 히트 평가 이 기술은 이렇게 높지 않습니다.고 투기 실패 원인 파이프라인 마구간은 큰 성능이 저하됩니다.(이것은 완전하여 CPU 를 구현합니다.모바일 CPU 으로 알려져 있지 않은 이런 종류의 최적화를 저장하는 에너지)

기본적으로 C#정적으로 컴파일된 언어입니다.하지만 항상 그렇지는 않습니다.지 알고 정확한 조건과 이것은 전적으로 컴파일러 구현합니다.일부 컴파일러를 제거할 수 있는 가능성의 동적으로 파견을 방지하는 방법을 재정의 경우는 방법으로 표시 sealed.멍청한 컴파일러되지 않을 수도 있습니다.이것은 성능의 혜택 sealed.


이 답변(왜 그것은 빠른 프로세스 정렬된 배열보다는 배열? 로)설명하는 분기 예측프............

마킹 클래스 sealed 해야 성능에 영향을 미치지 않습니다.

가 있는 경우 csc 해야 할 수도 있습 방출 callvirt opcode 신 call opcode.그러나,이러한 경우는 드물다.

그리고 그것은 나에게 보인다는 JIT 할 수 있어야한다 방출 같은 비상 함수 호출에 대한 callvirt 는 것에 대한 call, 는 경우,그것이 알고 있는 클래스가 없 서브 클래스(아직).는 경우 단지 하나의 구현 방법은 존재는 없 포인트 적재적소에서 vtable—은 하나의 구현이 직접 있습니다.그 문제에 관해서는,JIT 할 수 있도록 인라인 기능입니다.

그것의 비트에 도박 JIT 의 부분 인 경우 때문에 하위 클래스 나중에 로드,JIT 것을 버려야는 컴퓨터 코드를 컴파일 코드를 다시 방출하는 진정한 가상 통화합니다.나의 추측이 일어나지 않는 자주습니다.

(예,VM 디자이너들이 정말로 적극적으로 추구하는 이 작은 성능을 승리합니다.)

밀봉 클래스 제공 성능을 개선합니다.이후로 밀봉된 등 유래된 것,어떤 가상 멤버로 설정할 수 있습니 비상 회원입니다.

물론 우리가 얘기하는 정말 작은 이익입니다.나지 않을 표시하는 등으로 밀봉을 성능을 개선하지 않는 한 프로파일링 그것을 공개할 수 있습니다.

<off-topic-rant>

혐오 밀봉 클래스입니다.는 경우에도 성능의 혜택은 놀라운 있습니다(이는 내가 의심),그들은 파괴 객체지향 모델을 방지하여 재사용을 통해 상속입니다.예를 들어,스레드 등이 밀봉된다.는 동안 나는 볼 수 있습니다 볼 수 있는 원하는 스레드 최대한 효율적으로 사용할 수 있는 상상 시나리오를 수 있는 서브 클래스는 스레드가 큰 혜택입니다.클래스를 만든,당신 인감의 클래스를 위한"performance"이유 제공해 주십시오 인터페이스 적어도 그래서 우리는 없을 감싸고 교체하는 곳에서 우리는 기능이 필요 당신을 잊어버렸습니다.

예제: SafeThread 을 마무리 하였습니다 실 클래스 때문에 쓰레드가 봉인 없 IThread 인터페이스;SafeThread 트랩 자동으로 처리되지 않은 예외에 스레드가에서 완전히 실 클래스입니다.[그리고,처리되지 않은 예외 이벤트 픽업 예외 처리되지 않은 보조 스레드].

</off-topic-rant>

나는"고려 밀봉된"클래스 일반적인 경우와 나는 항상 이유를 생략하"밀봉한"키워드를 사용합니다.

가장 중요한 이유로 나를 위해습니다:

a)더 나은 컴파일 타임 검사(주조하는 인터페이스 구현되지 않았습니다에서 감지 될 컴파일한 시간에서뿐만 아니라,런타임)

그리고,최고 이유:

b)Abuse 의 수업은 가능하지 않는 방법

나는 Microsoft 만든 것 밀봉""표준이 없다"개봉".

@Vaibhav,어떤 종류의 시험을 당신은 실행을 측정하는 성능은?

나는 하나의 사용 을 드릴 CLI 와 방법을 이해하는 밀봉된 클래스의 성능을 향상시킬 수 있습니다.

SSCLI(Rotor)
SSCLI:공동 소스 Common Language 인프라

일반적인 언어는 인프라 (CLI)에 ECMA 표준 에 대해 설명합의 핵심.NET Framework.Shared Source CLI (SSCLI)라고 알려져 있으로 회전,가 압축 아카이브의 소스 코드 작업의 구현 ECMA CLI,ECMA C#언어 명세,기술에서 의 중심 Microsoft's.NET 공합니다.

밀봉 클래스에서는 적어도 조금 더 빨리,하지만 때로는 할 수 있습 waayyy 빠른...면 JIT 최적화할 수 있는 인라인 호출하고 있는 가상 호출합니다.그래서,어디가 자주라고 하는 방법을 충분히 작게 인라인되는 확실히려 바다표범 어업은 클래스입니다.

그러나,가장 좋은 이유는 물개 클래스"라고 말하는 것이 나는 디자인하지 않았다는 이야에서 상속되는,그래서 나는 당신이 당신을 얻을 태워 가정에 의해 디자인 되었습니다 그래서,그리고 나지 않는 나 자신에 의해 점점 잠으로 구현하기 때문에 나는 당신이 그것에서 파생."

난 여기 있다고 말했 그들이 싫어 밀봉한 클래스 때문에 그들이 원하는 기회를 파생 아무것도에서...하지만 그것은 종종 가장 유지 보수 선...기 때문에 노래를 유도 잠금에서 당신보다 더 많이 노출되지 않습니다.그와 비슷한 말이"내가 싫어 있는 클래스의 개인원...저는 종종을 만들 수 없습니다 클래스는 무엇이고 싶지 않기 때문에 액세스할 수 있습니다." 캡슐화는 중요...바다표범 어업이 하나의 형태를 캡슐화합니다.

이 코드를 실행하고 당신이 볼 수는 밀봉된 수업은 2 시간이 더 빠르다:

class Program
{
    static void Main(string[] args)
    {
        Console.ReadLine();

        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < 10000000; i++)
        {
            new SealedClass().GetName();
        }
        watch.Stop();
        Console.WriteLine("Sealed class : {0}", watch.Elapsed.ToString());

        watch.Start();
        for (int i = 0; i < 10000000; i++)
        {
            new NonSealedClass().GetName();
        }
        watch.Stop();
        Console.WriteLine("NonSealed class : {0}", watch.Elapsed.ToString());

        Console.ReadKey();
    }
}

sealed class SealedClass
{
    public string GetName()
    {
        return "SealedClass";
    }
}

class NonSealedClass
{
    public string GetName()
    {
        return "NonSealedClass";
    }
}

출력:밀봉 클래스:00:00:00.1897568 NonSealed 클래스:00:00:00.3826678

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