C# Sealed Class Test 1

by Sam Allen - Updated January 17, 2010

You want to see if the keyword sealed in the C# programming language can improve the optimization and performance of your code targeting the .NET Framework. The keyword sealed provides a way to demand that the class not be inherited from, but it is also useful for performance optimization. Here we inspect the sealed keyword in the C# programming language, seeing how you can apply it to a regular interface implementation and that the JIT can optimize the virtual method dispatch better on a sealed class.

~~~ Sealed class benchmark results (C#) ~~~       
    See "Benchmark" section for the code compared.

TestA.GetNumber (regular): 2.490 ns
TestB.GetNumber (sealed):  2.162 ns    [faster]

Using sealed

First, applying the sealed keyword in the C# programming language tells the C# compiler to apply the "sealed" metadata decoration in the assembly of your class. The sealed keyword is a syntax hint that restricts class declarations that might build on top of your sealed class. Additionally, the JIT compiler can detect the sealed decoration and optimize method invocations better when it is used. This example demonstrates an interface with one method, and two classes. The first class, TestA, implements the interface but is not sealed, and the second class, TestB, implements the interface and has the sealed decoration.

--- Program that uses sealed class (C#) ---

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
    }
}

--- Output of the program ---

1
2

Difference with sealed class. The two classes that implement the ITest interface in the example are exactly the same except for a difference in the integer-literal stored in the GetNumber method (for demonstration) and the keyword sealed stored in the TestB declarator.

Virtual method dispatch

Here we note the mechanism by which the .NET Framework calls interface methods and other virtual methods. Programming languages that implement class-level polymorphism store a virtual method dispatch table and the runtime then looks for the method location during execution. In the .NET Framework, each type has a Type pointer on the managed heap and this is used for virtual method dispatch. You can read more about the interface type in the C# language.

(See Interface Program 1.)

Release optimizations

Here we mention that the JIT (just-in-time) optimizations in the .NET Framework are not always invoked, depending on the context of the execution environment. If you execute this program in the Visual Studio 2008 environment (in either Debug or Release mode), the optimization enabled by the keyword sealed is not applied. You can run the program outside of the debugger by clicking on the executable.

Benchmark

Here we see evidence of the small but measurable speedup allowed by the use of the keyword sealed in the C# programming language. The benchmark shows that for the very simplest interface methods, the sealed keyword can improve performance by about a third of a nanosecond per method invocation. For interface-heavy programs, the sealed keyword decoration can result in a speedup on all method calls with no downside.

=== Outer variables used in benchmark ===

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();

=== Information and results ===

Iterations: 1000000 * 100
Notes:      Five method calls in inner loops were done together.
            Results take this into account and divide by 5.
            Stopwatch figures are converted into nanoseconds.
            Both methods return the value 1 in GetNumber().
            Based on .NET Framework 3.5 SP1.

(See Convert Nanoseconds, Microseconds, and Milliseconds.)

Measure It!

Here we mention an excellent tool developed by Vance Morrison of the .NET Runtime team, called MeasureIt. This tool provides an easy way to instantly benchmark many primitive operations on the present .NET Framework installed. Because it is an actual executable, it is always up-to-date with your current installation. The MeasureIt tool on the author's system also reports a speedup with sealed class interface calls.

(Visit blogs.msdn.com.)

Summary

Here we looked at the keyword sealed in the C# programming language and applied it to a class where it produced a measurable speedup on all method invocations. We noted the basics of virtual method dispatch in the .NET Framework and demonstrated the correctness of the keyword; the optimizations applied in various execution environments; and an optimization tool developed at Microsoft that also proves the benefits of the keyword sealed.

(Do not copy this page.)

Dot Net Perls | Search
Classes | Constructor Overload (This) | Global Variable Use | Indexer Example | Interface Program 1 | Static Constructor
C# | SaveFileDialog Tutorial | IntegralHeight Property (Windows Forms) | Array.FindIndex Method | File.Replace Method
© 2010 Sam Allen. All rights reserved.
Dot Net Perls | Sam Allen