0

From the IL perspective, what are the main differences (performance wise) between a local Dim variable and a local Static variable?

I've always thought that Dim would allocate storage space every time, whilst Static would allocate storage space only once, hence faster. But as you can see below, this is not the case.

  • A: Dim
  • B: Static

Chart

Public Class Form1

    Public Sub New()
        Me.InitializeComponent()
        Dim b As New Button() With {.Text = "Run", .Height = 30, .Location = New Point(10, 10)}
        AddHandler b.Click, AddressOf Me.Run
        Me.Controls.Add(b)
    End Sub

    Private Sub Run(sender As Object, e As EventArgs)

        Dim count As Integer = 10000
        Dim watch As New Stopwatch()
        Dim list As New Test(Of Control)(count)
        Dim last As Control = list.Items(count - 1)
        Dim a, b As Double, i As Integer

        For i = 1 To 10000
            watch.Restart()
            list.IndexOfA(last)
            a += watch.Elapsed.TotalMilliseconds
        Next

        For i = 1 To 10000
            watch.Restart()
            list.IndexOfB(last)
            b += watch.Elapsed.TotalMilliseconds
        Next

        watch.Stop()
        Array.ForEach(Of Control)(list.Items, Sub(c As Control) c.Dispose())
        list = Nothing

        MessageBox.Show(String.Format("A: {0}{1}B: {2}", a.ToString("F4"), Environment.NewLine, b.ToString("F4")))

    End Sub

    Public Class Test(Of T As {Class, New})

        Public Sub New(count)
            If (count < 0) Then Throw New ArgumentOutOfRangeException("count")
            Dim items As T() = New T(count - 1) {}
            For index As Integer = (count - 1) To 0 Step -1
                items(index) = New T()
            Next
            Me.Items = items
        End Sub

        Public Function IndexOfA(item As T) As Integer
            Dim index As Integer
            Dim length As Integer
            Dim item2 As T
            length = (Me.Items.Length - 1)
            For index = 0 To length
                item2 = Me.Items(index)
                If (item2 Is item) Then
                    Return index
                End If
            Next
            Return -1
        End Function

        Public Function IndexOfB(item As T) As Integer
            Static index As Integer
            Static length As Integer
            Static item2 As T
            length = (Me.Items.Length - 1)
            For index = 0 To length
                item2 = Me.Items(index)
                If (item2 Is item) Then
                    Return index
                End If
            Next
            Return -1
        End Function

        Public ReadOnly Items As T()

    End Class

End Class

Edit

As per comment, I've edited the code so it don't "restart the stopwatch at every loop iteration".

watch.Start()
For i = 1 To 10000
    list.IndexOfA(last)
Next
watch.Stop()
a = watch.Elapsed.TotalMilliseconds

watch.Restart()
For i = 1 To 10000 
    list.IndexOfB(last)
Next
watch.Stop()
b = watch.Elapsed.TotalMilliseconds

The results are almost the same:

  • A: 358,3624
  • B: 538.8570
Bjørn-Roger Kringsjå
  • 9,849
  • 6
  • 36
  • 64

2 Answers2

5

The main difference in performance is not how the variables are allocated, it's in how they are accessed.

Local variables are allocated on the stack, which takes no time at all. Literally. The allocation is done by moving the stack pointer, and that is done anyway to create a stack frame for the method, so allocating local variables doesn't take any more time.

Static variables in an instance method are allocated as part of the data for the class, and that is done only once in this case. Allocating another variable only means that more data is allocated, so that doesn't increase the time.

Accessing the variables is a different story. A local variable is accessed by addressing part of the stack frame, which is easy. A static variable on the other hand is accessed by getting a pointer to the static data of the class, and then addressing the variable at an offset from that. That means that every access to a static variable needs a few more instructions.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Yes, and local variables can be optimized by the use of CPU registers instead of stack space, which makes them even more efficient. – Olivier Jacot-Descombes May 11 '14 at 19:36
  • Local static variables are allocated per-instance if they occur within an instance method and as part of the static data if they occur within a static method. You can easily test this. – Dave Doknjas May 11 '14 at 19:37
  • @DaveDoknjas: That makes no difference, as there is only one instance. – Guffa May 11 '14 at 19:38
  • @Guffa: My comment was regarding your statement that "static variables are allocated as part of the static data for the class" - this clearly only applies to VB local static variables within Shared methods, not instance methods. – Dave Doknjas May 11 '14 at 19:42
  • @DaveDoknjas: You may be right about that detail, but it still has no relevance for the question. – Guffa May 11 '14 at 19:44
  • @Guffa (and others) I really appreciate your answers and comments. I'll give you a +1. But if you don't mind I'll keep this question open for a while (not days - and as I'm not familiar with CLR) and let the community have its say. – Bjørn-Roger Kringsjå May 11 '14 at 19:56
-2

VB local static variables are allocated once per instance if they occur within an instance method. They are only allocated once overall if they occur within a Shared method.

Dave Doknjas
  • 6,394
  • 1
  • 15
  • 28
  • To the downvoter: The information I provided is correct - please explain the down vote. – Dave Doknjas May 11 '14 at 19:35
  • I'm not the downvoter, but while your answer is correct, it does not give an answer to the question. It does not explain the observed difference in the timing. – Olivier Jacot-Descombes May 11 '14 at 19:39
  • @DaveDoknjas I'm not the downvoter neither, and I appreciate your answer. But from MSDN: _"When you declare a static variable in a procedure that isn't Shared, only one copy of the variable is available for each instance of the class."_ And as you can see in my code, I'm only creating one instance of `Test` once. – Bjørn-Roger Kringsjå May 11 '14 at 20:04