<p>I have come across a lot of optimization tips which say that you should mark your classes as sealed to get extra performance benefits.</p>

<p>I ran some tests to check the performance differential and found none. Am I doing something wrong? Am I missing the case where sealed classes will give better results?</p>

<p>Has anyone run tests and seen a difference?</p>

<p>Help me learn :)</p>

[{'answer_id': 2183, 'author': 'Lasse V. Karlsen', 'author_id': 267, 'author_profile': 'https://Stackoverflow.com/users/267', 'pm_score': 7, 'selected': True, 'text': '<p>The JITter will sometimes use non-virtual calls to methods in sealed classes since there is no way they can be extended further.</p>\n\n<p>There are complex rules regarding calling type, virtual/nonvirtual, and I don\'t know them all so I can\'t really outline them for you, but if you google for sealed classes and virtual methods you might find some articles on the topic.</p>\n\n<p>Note that any kind of performance benefit you would obtain from this level of optimization should be regarded as last-resort, always optimize on the algorithmic level before you optimize on the code-level.</p>\n\n<p>Here\'s one link mentioning this: <a href="http://codebetter.com/blogs/patricksmacchia/archive/2008/01/05/rambling-on-the-sealed-keyword.aspx" rel="noreferrer">Rambling on the sealed keyword</a></p>\n'}, {'answer_id': 2189, 'author': 'Karl Seguin', 'author_id': 34, 'author_profile': 'https://Stackoverflow.com/users/34', 'pm_score': 2, 'selected': False, 'text': "<p>Sealed classes <em>should</em> provide a performance improvement. Since a sealed class cannot be derived, any virtual members can be turned into non-virtual members.</p>\n\n<p>Of course, we're talking really small gains. I wouldn't mark a class as sealed just to get a performance improvement unless profiling revealed it to be a problem.</p>\n"}, {'answer_id': 202584, 'author': 'Steven A. Lowe', 'author_id': 9345, 'author_profile': 'https://Stackoverflow.com/users/9345', 'pm_score': 3, 'selected': False, 'text': '<p>&lt;off-topic-rant&gt;</p>\n\n<p>I <em>loathe</em> sealed classes. Even if the performance benefits are astounding (which I doubt), they <em>destroy</em> the object-oriented model by preventing reuse via inheritance. For example, the Thread class is sealed. While I can see that one might want threads to be as efficient as possible, I can also imagine scenarios where being able to subclass Thread would have great benefits.\nClass authors, if you <em>must</em> seal your classes for "performance" reasons, <strong>please provide an interface</strong> at the very least so we don\'t have to wrap-and-replace everywhere that we need a feature you forgot.</p>\n\n<p>Example: <a href="http://www.codeproject.com/KB/threads/SafeThread.aspx" rel="nofollow noreferrer">SafeThread</a> had to wrap the Thread class because Thread is sealed and there is no IThread interface; SafeThread automatically traps unhandled exceptions on threads, something completely missing from the Thread class. [and no, the unhandled exception events do <em>not</em> pick up unhandled exceptions in secondary threads].</p>\n\n<p>&lt;/off-topic-rant&gt;</p>\n'}, {'answer_id': 390627, 'author': 'Cameron MacFarland', 'author_id': 3820, 'author_profile': 'https://Stackoverflow.com/users/3820', 'pm_score': 7, 'selected': False, 'text': '<p>The answer was no, sealed classes do not perform better than non-sealed.</p>\n<p>2021: The answer is now yes there are performance benefits to sealing a class.</p>\n<p>Sealing a class may not always provide a performance boost, but the dotnet team are adopting the rule of sealing all internal classes to give the optimiser the best chance.</p>\n<p>For details you can read <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#peanut-butter" rel="noreferrer">https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#peanut-butter</a></p>\n<p>Old answer below.</p>\n<p>The issue comes down to the <code>call</code> vs <code>callvirt</code> IL op codes. <code>Call</code> is faster than <code>callvirt</code>, and <code>callvirt</code> is mainly used when you don\'t know if the object has been subclassed. So people assume that if you seal a class all the op codes will change from <code>calvirts</code> to <code>calls</code> and will be faster.</p>\n<p>Unfortunately <code>callvirt</code> does other things that make it useful too, like checking for null references. This means that even if a class is sealed, the reference might still be null and thus a <code>callvirt</code> is needed. You can get around this (without needing to seal the class), but it becomes a bit pointless.</p>\n<p>Structs use <code>call</code> because they cannot be subclassed and are never null.</p>\n<p>See this question for more information:</p>\n<p><a href="https://stackoverflow.com/questions/193939/call-and-callvirt">Call and callvirt</a></p>\n'}, {'answer_id': 1769457, 'author': 'Jason Orendorff', 'author_id': 94977, 'author_profile': 'https://Stackoverflow.com/users/94977', 'pm_score': 2, 'selected': False, 'text': "<p>Marking a class <code>sealed</code> should have no performance impact.</p>\n\n<p>There are cases where <code>csc</code> might have to emit a <code>callvirt</code> opcode instead of a <code>call</code> opcode. However, it seems those cases are rare.</p>\n\n<p>And it seems to me that the JIT should be able to emit the same non-virtual function call for <code>callvirt</code> that it would for <code>call</code>, if it knows that the class doesn't have any subclasses (yet). If only one implementation of the method exists, there's no point loading its address from a vtable—just call the one implementation directly. For that matter, the JIT can even inline the function.</p>\n\n<p>It's a bit of a gamble on the JIT's part, because if a subclass <em>is</em> later loaded, the JIT will have to throw away that machine code and compile the code again, emitting a real virtual call. My guess is this doesn't happen often in practice.</p>\n\n<p>(And yes, VM designers really do aggressively pursue these tiny performance wins.)</p>\n"}, {'answer_id': 1804953, 'author': 'RuslanG', 'author_id': 219591, 'author_profile': 'https://Stackoverflow.com/users/219591', 'pm_score': -1, 'selected': False, 'text': '<p>Run this code and you\'ll see that sealed classes are 2 times faster:</p>\n\n<pre><code>class Program\n{\n    static void Main(string[] args)\n    {\n        Console.ReadLine();\n\n        var watch = new Stopwatch();\n        watch.Start();\n        for (int i = 0; i &lt; 10000000; i++)\n        {\n            new SealedClass().GetName();\n        }\n        watch.Stop();\n        Console.WriteLine("Sealed class : {0}", watch.Elapsed.ToString());\n\n        watch.Start();\n        for (int i = 0; i &lt; 10000000; i++)\n        {\n            new NonSealedClass().GetName();\n        }\n        watch.Stop();\n        Console.WriteLine("NonSealed class : {0}", watch.Elapsed.ToString());\n\n        Console.ReadKey();\n    }\n}\n\nsealed class SealedClass\n{\n    public string GetName()\n    {\n        return "SealedClass";\n    }\n}\n\nclass NonSealedClass\n{\n    public string GetName()\n    {\n        return "NonSealedClass";\n    }\n}\n</code></pre>\n\n<p>output:\nSealed class : 00:00:00.1897568\nNonSealed class : 00:00:00.3826678</p>\n'}, {'answer_id': 3397483, 'author': 'Turing Complete', 'author_id': 372920, 'author_profile': 'https://Stackoverflow.com/users/372920', 'pm_score': 2, 'selected': False, 'text': '<p>I consider "sealed" classes the normal case and I ALWAYS have a reason to omit the "sealed" keyword.</p>\n\n<p>The most important reasons for me are:</p>\n\n<p>a) Better compile time checks (casting to interfaces not implemented will be detected at compile time, not only at runtime)</p>\n\n<p>and, top reason:</p>\n\n<p>b) Abuse of my classes is not possible that way</p>\n\n<p>I wish Microsoft would have made "sealed" the standard, not "unsealed".</p>\n'}, {'answer_id': 4888000, 'author': 'eonil', 'author_id': 246776, 'author_profile': 'https://Stackoverflow.com/users/246776', 'pm_score': 5, 'selected': False, 'text': '<p>As I know, there is no guarantee of performance benefit. But there is <strong>a chance to decrease performance penalty under some specific condition</strong> with sealed method. (sealed class makes all methods to be sealed.)</p>\n\n<p>But it\'s up to compiler implementation and execution environment. </p>\n\n<hr>\n\n<h1>Details</h1>\n\n<p>Many of modern CPUs use long pipeline structure to increase performance. Because CPU is incredibly faster than memory, CPU has to prefetch code from memory to accelerate pipeline. If the code is not ready at proper time, the pipelines will be idle.</p>\n\n<p>There is a big obstacle called <strong><a href="http://en.wikipedia.org/wiki/Dynamic_dispatch" rel="nofollow noreferrer">dynamic dispatch</a></strong> which disrupts this \'prefetching\' optimization. You can understand this as just a conditional branching. </p>\n\n<pre><code>// Value of `v` is unknown,\n// and can be resolved only at runtime.\n// CPU cannot know which code to prefetch.\n// Therefore, just prefetch any one of a() or b().\n// This is *speculative execution*.\nint v = random();\nif (v==1) a();\nelse b();\n</code></pre>\n\n<p>CPU cannot prefetch next code to execute in this case because the next code position is unknown until the condition is resolved. So this makes <a href="http://en.wikipedia.org/wiki/Hazard_(computer_architecture)" rel="nofollow noreferrer">hazard</a> causes pipeline idle. And performance penalty by idle is huge in regular.</p>\n\n<p>Similar thing happen in case of method overriding. Compiler may determine proper method overriding for current method call, but sometimes it\'s impossible. In this case, proper method can be determined only at runtime. This is also a case of dynamic dispatch, and, a main reason of dynamically-typed languages are generally slower than statically-typed languages.</p>\n\n<p>Some CPU (including recent Intel\'s x86 chips) uses technique called <strong><a href="http://en.wikipedia.org/wiki/Speculative_execution#Processors" rel="nofollow noreferrer">speculative execution</a></strong> to utilize pipeline even on the situation. Just prefetch one of execution path. But hit rate of this technique is not so high. And speculation failure causes pipeline stall which also makes huge performance penalty. (this is completely by CPU implementation. some mobile CPU is known as does not this kind of optimization to save energy) </p>\n\n<p>Basically, C# is a statically compiled language. But not always. I don\'t know exact condition and this is entirely up to compiler implementation. Some compilers can eliminate possibility of dynamic dispatch by preventing method overriding if the method is marked as <code>sealed</code>. Stupid compilers may not.\nThis is the performance benefit of the <code>sealed</code>.</p>\n\n<hr>\n\n<p>This answer (<a href="https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array/11227902#11227902">Why is it faster to process a sorted array than an unsorted array?</a>) is describing the branch prediction a lot better. </p>\n'}, {'answer_id': 7619687, 'author': 'Brian Kennedy', 'author_id': 968565, 'author_profile': 'https://Stackoverflow.com/users/968565', 'pm_score': 2, 'selected': False, 'text': '<p>sealed classes will be at least a tiny bit faster, but sometimes can be waayyy faster... if the JIT Optimizer can inline calls that would have otherwise been virtual calls.  So, where there\'s oft-called methods that are small enough to be inlined, definitely consider sealing the class.</p>\n\n<p>However, the best reason to seal a class is to say "I didn\'t design this to be inherited from, so I\'m not going to let you get burned by assuming it was designed to be so, and I\'m not going to burn myself by getting locked into an implementation because I let you derive from it."</p>\n\n<p>I know some here have said they hate sealed classes because they want the opportunity to derive from anything... but that is OFTEN not the most maintainable choice... because exposing a class to derivation locks you in a lot more than not exposing all that.  Its similar to saying "I loathe classes that have private members... I often can\'t make the class do what I want because I don\'t have access."  Encapsulation is important... sealing is one form of encapsulation.</p>\n'}, {'answer_id': 9368148, 'author': 'Orion Edwards', 'author_id': 234, 'author_profile': 'https://Stackoverflow.com/users/234', 'pm_score': 5, 'selected': False, 'text': '<p>Update: As of .NET Core 2.0 and .NET Desktop 4.7.1, the CLR now supports devirtualization. It can take methods in sealed classes and replace virtual calls with direct calls - and it can also do this for non-sealed classes if it can figure out it\'s safe to do so.</p>\n\n<p>In such a case (a sealed class that the CLR couldn\'t otherwise detect as safe to devirtualise), a sealed class should actually offer some kind of performance benefit.</p>\n\n<p>That said, I wouldn\'t think it\'d be worth worrying about <em>unless</em> you had already profiled the code and determined that you were in a particularly hot path being called millions of times, or something like that:</p>\n\n<p><a href="https://blogs.msdn.microsoft.com/dotnet/2017/06/29/performance-improvements-in-ryujit-in-net-core-and-net-framework/" rel="noreferrer">https://blogs.msdn.microsoft.com/dotnet/2017/06/29/performance-improvements-in-ryujit-in-net-core-and-net-framework/</a></p>\n\n<hr>\n\n<p>Original Answer:</p>\n\n<p>I made the following test program, and then decompiled it using Reflector to see what MSIL code was emitted.</p>\n\n<pre><code>public class NormalClass {\n    public void WriteIt(string x) {\n        Console.WriteLine("NormalClass");\n        Console.WriteLine(x);\n    }\n}\n\npublic sealed class SealedClass {\n    public void WriteIt(string x) {\n        Console.WriteLine("SealedClass");\n        Console.WriteLine(x);\n    }\n}\n\npublic static void CallNormal() {\n    var n = new NormalClass();\n    n.WriteIt("a string");\n}\n\npublic static void CallSealed() {\n    var n = new SealedClass();\n    n.WriteIt("a string");\n}\n</code></pre>\n\n<p>In all cases, the C# compiler (Visual studio 2010 in Release build configuration) emits identical MSIL, which is as follows:</p>\n\n<pre><code>L_0000: newobj instance void &lt;NormalClass or SealedClass&gt;::.ctor()\nL_0005: stloc.0 \nL_0006: ldloc.0 \nL_0007: ldstr "a string"\nL_000c: callvirt instance void &lt;NormalClass or SealedClass&gt;::WriteIt(string)\nL_0011: ret \n</code></pre>\n\n<p>The oft-quoted reason that people say sealed provides performance benefits is that the compiler knows the class isn\'t overriden, and thus can use <code>call</code> instead of <code>callvirt</code> as it doesn\'t have to check for virtuals, etc. As proven above, this is not true.</p>\n\n<p>My next thought was that even though the MSIL is identical, perhaps the JIT compiler treats sealed classes differently?</p>\n\n<p>I ran a release build under the visual studio debugger and viewed the decompiled x86 output. In both cases, the x86 code was identical, with the exception of class names and function memory addresses (which of course must be different). Here it is</p>\n\n<pre><code>//            var n = new NormalClass();\n00000000  push        ebp \n00000001  mov         ebp,esp \n00000003  sub         esp,8 \n00000006  cmp         dword ptr ds:[00585314h],0 \n0000000d  je          00000014 \n0000000f  call        70032C33 \n00000014  xor         edx,edx \n00000016  mov         dword ptr [ebp-4],edx \n00000019  mov         ecx,588230h \n0000001e  call        FFEEEBC0 \n00000023  mov         dword ptr [ebp-8],eax \n00000026  mov         ecx,dword ptr [ebp-8] \n00000029  call        dword ptr ds:[00588260h] \n0000002f  mov         eax,dword ptr [ebp-8] \n00000032  mov         dword ptr [ebp-4],eax \n//            n.WriteIt("a string");\n00000035  mov         edx,dword ptr ds:[033220DCh] \n0000003b  mov         ecx,dword ptr [ebp-4] \n0000003e  cmp         dword ptr [ecx],ecx \n00000040  call        dword ptr ds:[0058827Ch] \n//        }\n00000046  nop \n00000047  mov         esp,ebp \n00000049  pop         ebp \n0000004a  ret \n</code></pre>\n\n<p>I then thought perhaps running under the debugger causes it to perform less aggressive optimization?</p>\n\n<p>I then ran a standalone release build executable outside of any debugging environments, and used WinDBG + SOS to break in after the program had completed, and view the dissasembly of the JIT compiled x86 code.</p>\n\n<p>As you can see from the code below, when running outside the debugger the JIT compiler is more aggressive, and it has inlined the <code>WriteIt</code> method straight into the caller.\nThe crucial thing however is that it was identical when calling a sealed vs non-sealed class. There is no difference whatsoever between a sealed or nonsealed class.</p>\n\n<p>Here it is when calling a normal class:</p>\n\n<pre><code>Normal JIT generated code\nBegin 003c00b0, size 39\n003c00b0 55              push    ebp\n003c00b1 8bec            mov     ebp,esp\n003c00b3 b994391800      mov     ecx,183994h (MT: ScratchConsoleApplicationFX4.NormalClass)\n003c00b8 e8631fdbff      call    00172020 (JitHelp: CORINFO_HELP_NEWSFAST)\n003c00bd e80e70106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)\n003c00c2 8bc8            mov     ecx,eax\n003c00c4 8b1530203003    mov     edx,dword ptr ds:[3302030h] ("NormalClass")\n003c00ca 8b01            mov     eax,dword ptr [ecx]\n003c00cc 8b403c          mov     eax,dword ptr [eax+3Ch]\n003c00cf ff5010          call    dword ptr [eax+10h]\n003c00d2 e8f96f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)\n003c00d7 8bc8            mov     ecx,eax\n003c00d9 8b1534203003    mov     edx,dword ptr ds:[3302034h] ("a string")\n003c00df 8b01            mov     eax,dword ptr [ecx]\n003c00e1 8b403c          mov     eax,dword ptr [eax+3Ch]\n003c00e4 ff5010          call    dword ptr [eax+10h]\n003c00e7 5d              pop     ebp\n003c00e8 c3              ret\n</code></pre>\n\n<p>Vs a sealed class:</p>\n\n<pre><code>Normal JIT generated code\nBegin 003c0100, size 39\n003c0100 55              push    ebp\n003c0101 8bec            mov     ebp,esp\n003c0103 b90c3a1800      mov     ecx,183A0Ch (MT: ScratchConsoleApplicationFX4.SealedClass)\n003c0108 e8131fdbff      call    00172020 (JitHelp: CORINFO_HELP_NEWSFAST)\n003c010d e8be6f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)\n003c0112 8bc8            mov     ecx,eax\n003c0114 8b1538203003    mov     edx,dword ptr ds:[3302038h] ("SealedClass")\n003c011a 8b01            mov     eax,dword ptr [ecx]\n003c011c 8b403c          mov     eax,dword ptr [eax+3Ch]\n003c011f ff5010          call    dword ptr [eax+10h]\n003c0122 e8a96f106f      call    mscorlib_ni+0x2570d0 (6f4c70d0) (System.Console.get_Out(), mdToken: 060008fd)\n003c0127 8bc8            mov     ecx,eax\n003c0129 8b1534203003    mov     edx,dword ptr ds:[3302034h] ("a string")\n003c012f 8b01            mov     eax,dword ptr [ecx]\n003c0131 8b403c          mov     eax,dword ptr [eax+3Ch]\n003c0134 ff5010          call    dword ptr [eax+10h]\n003c0137 5d              pop     ebp\n003c0138 c3              ret\n</code></pre>\n\n<p>To me, this provides solid proof that there <em>cannot</em> be any performance improvement between calling methods on sealed vs non-sealed classes... I think I\'m happy now :-)</p>\n'}, {'answer_id': 60397512, 'author': 'Ivan Porta', 'author_id': 6613232, 'author_profile': 'https://Stackoverflow.com/users/6613232', 'pm_score': 1, 'selected': False, 'text': '<p>To really see them you need to analyze the <strong>JIT-Compiled cod</strong>e (last one).</p>\n\n<p><strong>C# Code</strong></p>\n\n<pre><code>public sealed class Sealed\n{\n    public string Message { get; set; }\n    public void DoStuff() { }\n}\npublic class Derived : Base\n{\n    public sealed override void DoStuff() { }\n}\npublic class Base\n{\n    public string Message { get; set; }\n    public virtual void DoStuff() { }\n}\nstatic void Main()\n{\n    Sealed sealedClass = new Sealed();\n    sealedClass.DoStuff();\n    Derived derivedClass = new Derived();\n    derivedClass.DoStuff();\n    Base BaseClass = new Base();\n    BaseClass.DoStuff();\n}\n</code></pre>\n\n<p><strong>MIL Code</strong></p>\n\n<pre><code>.method private hidebysig static void  Main() cil managed\n{\n  .entrypoint\n  // Code size       41 (0x29)\n  .maxstack  8\n  IL_0000:  newobj     instance void ConsoleApp1.Program/Sealed::.ctor()\n  IL_0005:  callvirt   instance void ConsoleApp1.Program/Sealed::DoStuff()\n  IL_000a:  newobj     instance void ConsoleApp1.Program/Derived::.ctor()\n  IL_000f:  callvirt   instance void ConsoleApp1.Program/Base::DoStuff()\n  IL_0014:  newobj     instance void ConsoleApp1.Program/Base::.ctor()\n  IL_0019:  callvirt   instance void ConsoleApp1.Program/Base::DoStuff()\n  IL_0028:  ret\n} // end of method Program::Main\n</code></pre>\n\n<p><strong>JIT- Compiled Code</strong></p>\n\n<pre><code>--- C:\\Users\\Ivan Porta\\source\\repos\\ConsoleApp1\\Program.cs --------------------\n        {\n0066084A  in          al,dx  \n0066084B  push        edi  \n0066084C  push        esi  \n0066084D  push        ebx  \n0066084E  sub         esp,4Ch  \n00660851  lea         edi,[ebp-58h]  \n00660854  mov         ecx,13h  \n00660859  xor         eax,eax  \n0066085B  rep stos    dword ptr es:[edi]  \n0066085D  cmp         dword ptr ds:[5842F0h],0  \n00660864  je          0066086B  \n00660866  call        744CFAD0  \n0066086B  xor         edx,edx  \n0066086D  mov         dword ptr [ebp-3Ch],edx  \n00660870  xor         edx,edx  \n00660872  mov         dword ptr [ebp-48h],edx  \n00660875  xor         edx,edx  \n00660877  mov         dword ptr [ebp-44h],edx  \n0066087A  xor         edx,edx  \n0066087C  mov         dword ptr [ebp-40h],edx  \n0066087F  nop  \n            Sealed sealedClass = new Sealed();\n00660880  mov         ecx,584E1Ch  \n00660885  call        005730F4  \n0066088A  mov         dword ptr [ebp-4Ch],eax  \n0066088D  mov         ecx,dword ptr [ebp-4Ch]  \n00660890  call        00660468  \n00660895  mov         eax,dword ptr [ebp-4Ch]  \n00660898  mov         dword ptr [ebp-3Ch],eax  \n            sealedClass.DoStuff();\n0066089B  mov         ecx,dword ptr [ebp-3Ch]  \n0066089E  cmp         dword ptr [ecx],ecx  \n006608A0  call        00660460  \n006608A5  nop  \n            Derived derivedClass = new Derived();\n006608A6  mov         ecx,584F3Ch  \n006608AB  call        005730F4  \n006608B0  mov         dword ptr [ebp-50h],eax  \n006608B3  mov         ecx,dword ptr [ebp-50h]  \n006608B6  call        006604A8  \n006608BB  mov         eax,dword ptr [ebp-50h]  \n006608BE  mov         dword ptr [ebp-40h],eax  \n            derivedClass.DoStuff();\n006608C1  mov         ecx,dword ptr [ebp-40h]  \n006608C4  mov         eax,dword ptr [ecx]  \n006608C6  mov         eax,dword ptr [eax+28h]  \n006608C9  call        dword ptr [eax+10h]  \n006608CC  nop  \n            Base BaseClass = new Base();\n006608CD  mov         ecx,584EC0h  \n006608D2  call        005730F4  \n006608D7  mov         dword ptr [ebp-54h],eax  \n006608DA  mov         ecx,dword ptr [ebp-54h]  \n006608DD  call        00660490  \n006608E2  mov         eax,dword ptr [ebp-54h]  \n006608E5  mov         dword ptr [ebp-44h],eax  \n            BaseClass.DoStuff();\n006608E8  mov         ecx,dword ptr [ebp-44h]  \n006608EB  mov         eax,dword ptr [ecx]  \n006608ED  mov         eax,dword ptr [eax+28h]  \n006608F0  call        dword ptr [eax+10h]  \n006608F3  nop  \n        }\n0066091A  nop  \n0066091B  lea         esp,[ebp-0Ch]  \n0066091E  pop         ebx  \n0066091F  pop         esi  \n00660920  pop         edi  \n00660921  pop         ebp  \n\n00660922  ret  \n</code></pre>\n\n<p>While the creation of the objects is the same, the instruction executed to invoke the methods of the sealed and derived/base class are slightly different. After moving data into registers or RAM (mov instruction), the invoke of the sealed method, execute a comparison between dword ptr [ecx],ecx (cmp instruction) and then call the method while the derived/base class execute directly the method..</p>\n\n<p>According to the report written by Torbj¨orn Granlund, <strong>Instruction latencies and throughput for AMD and Intel x86 processors</strong>, the speed of the following instruction in a Intel Pentium 4 are:</p>\n\n<ul>\n<li><strong>mov</strong>: has 1 cycle as latency and the processor can sustain 2.5 instructions per cycle of this type</li>\n<li><strong>cmp</strong>: has 1 cycle as latency and the processor can sustain 2 instructions per cycle of this type</li>\n</ul>\n\n<p><strong>Link</strong>: <a href="https://gmplib.org/~tege/x86-timing.pdf" rel="nofollow noreferrer">https://gmplib.org/~tege/x86-timing.pdf</a></p>\n\n<p>This mean that, <strong>ideally</strong>, the time needed to invoke a sealed method is 2 cycles while the time needed to invoke a derived or base class method is 3 cycles. </p>\n\n<p>The optimization of the compilers have made the difference between the performances of a sealed and not-sealed classed so low that we are talking about processor circles and for this reason are irrelevant for the majority of applications.</p>\n'}, {'answer_id': 70065177, 'author': 'asaf92', 'author_id': 6104191, 'author_profile': 'https://Stackoverflow.com/users/6104191', 'pm_score': 2, 'selected': False, 'text': '<p><a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#peanut-butter" rel="nofollow noreferrer">Starting from .NET 6.0 the answer is yes.</a></p>\n<p>Sealing a class can help the JIT de-virtualize calls, resulting in less overhead when calling a method. This has additional benefits, because the de-virtualized call can be inlined by the JIT if necessary, which can also lead to constant folding.</p>\n<p>For example, in this code from the MSDN article:</p>\n<pre><code>[Benchmark(Baseline = true)]\npublic int NonSealed() =&gt; _nonSealed.M() + 42;\n\n[Benchmark]\npublic int Sealed() =&gt; _sealed.M() + 42;\n\npublic class BaseType\n{\n    public virtual int M() =&gt; 1;\n}\n\npublic class NonSealedType : BaseType\n{\n    public override int M() =&gt; 2;\n}\n\npublic sealed class SealedType : BaseType\n{\n    public override int M() =&gt; 2;\n}\n</code></pre>\n<p>The &quot;NonSealed&quot; benchmark runs in 0.9837ns, but the &quot;Sealed&quot; method doesn\'t take more time than a function that simply returns a constant value. This is due to constant folding.</p>\n<p>Type checking sealed classes also has performance benefits, like in this code from the MSDN article:</p>\n<pre><code>private object _o = &quot;hello&quot;;\n\n[Benchmark(Baseline = true)]\npublic bool NonSealed() =&gt; _o is NonSealedType;\n\n[Benchmark]\npublic bool Sealed() =&gt; _o is SealedType;\n\npublic class NonSealedType { }\npublic sealed class SealedType { }\n</code></pre>\n<p>Checking against a non-sealed type takes ~1.76ns, while checking the sealed type is only ~0.07ns.</p>\n<p>In fact, the .NET team made a policy to seal all the private and internal classes that can be sealed.</p>\n<p>Notice that we\'re dealing with saving less than 2 nanoseconds on a call, so the overhead of calling a virtual method is not gonna be the bottleneck most of the time. I think it\'s more appropriate for simple virtual getters or very short methods.</p>\n'}]
['https://Stackoverflow.com/questions/2134', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/380/']