-2

Does boxing cause performance issues in my code? How can I prevent boxing?

void Main()
{
    AreEqual<int>(12, 13);
}

public static bool AreEqual<T>(T a, T b)
{
    return a.Equals(b);
}

IL:

IL_0000:  nop         
IL_0001:  ldc.i4.s    0C 
IL_0003:  ldc.i4.s    0D 
IL_0005:  call        UserQuery.AreEqual
IL_000A:  pop         
IL_000B:  ret         

AreEqual:
IL_0000:  nop         
IL_0001:  ldarga.s    00 
IL_0003:  ldarg.1     
IL_0004:  box         01 00 00 1B 
IL_0009:  constrained. 01 00 00 1B 
IL_000F:  callvirt    System.Object.Equals
IL_0014:  stloc.0     // CS$1$0000
IL_0015:  br.s        IL_0017
IL_0017:  ldloc.0     // CS$1$0000
IL_0018:  ret       
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
Mohamad Shiralizadeh
  • 8,329
  • 6
  • 58
  • 93
  • 3
    Profile it. Is this the slow part of your application? – James Thorpe Jun 18 '15 at 08:30
  • 3
    didn't you post this code earlier under IL asking what the box command was? There were plenty of comments in that question pointing you to what boxing is and why it is happening in your code – Claies Jun 18 '15 at 08:31
  • 4
    Are you boxing several million objects per second? – CodesInChaos Jun 18 '15 at 08:33
  • i'm just curious.. Why vote down?! – Mohamad Shiralizadeh Jun 18 '15 at 08:45
  • Note that normally you would simply `EqualityComparer.Default.Equals(a, b)` and live happy. Probably slower than some other ways, but totally generic. – xanatos Jun 18 '15 at 09:04
  • _"Why vote down?"_ - because the first question makes no sense (we can't know if it'll cause performance issues for your specific application) and the second question should be better researched. – CodeCaster Jun 18 '15 at 09:13
  • 1
    And we don't like delete and repost of questions. You could have improved continued with the previous one. – H H Jun 18 '15 at 09:16

4 Answers4

4

Does Boxing cause performance issues in my code?

Only you can answer that. It's your code, it's your code's performance. To me, that isn't a problem, to you, it might be.

How can I prevent boxing?

By forcing the compiler to choose the correct overload. Your initial code calls object.Equals(object) (overridden in Int32.Equals(object)), because that's the only method that works for every unconstrained T, which requires boxing of the int argument you pass.

Int32.Equals(Int32) implements IEquatable<T>.Equals(T), so put that as constraint:

private static bool AreEqualEquatable<T>(T a, T b)
    where T : IEquatable<T>
{
    return a.Equals(b);
}

Which compiles to this IL:

IL_0000: nop
IL_0001: ldarga.s a
IL_0003: ldarg.1
IL_0004: constrained. !!T
IL_000a: callvirt instance bool class [mscorlib]System.IEquatable`1<!!T>::Equals(!0)
IL_000f: stloc.0
IL_0010: br.s IL_0012

IL_0012: ldloc.0
IL_0013: ret

Because the compiler will try to find the most specialized overload, in this case IEquatable<T>.Equals(T).

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
1

Sometimes it does, usually it doesn't.

You can't really predict performance problems this way. Do you have a specific program that is too slow and you suspect the problem is with boxing?

zmbq
  • 38,013
  • 14
  • 101
  • 171
1

See this hidden feature which could be used as a workaround. But - as always - be sure this isn't premature optimization.

Example Code:

   static void foo<T>(ref T value) {
        //This is the ONLY way to treat value as bool, without boxing/unboxing objects
        if(value is bool) {
            TypedReference reference = __makeref(value); //get reference
            bool boolVal = __refvalue(reference,bool);   //get primitive value
            __refvalue(reference, bool) = !boolVal;      //set primitive value
        } else {
            value = default(T);
        }
    }

I took the code partially from this thread

Community
  • 1
  • 1
Binkan Salaryman
  • 3,008
  • 1
  • 17
  • 29
1

Any additional operation that the computer do to perform a task will decrease performance, decrease in performance is one thing and performance issue is another thing. If you are trying to implement a high speed data structure with millions of data in it, it may cause performance issues but if you are just writing an information system which performs many queries on database and network then I don't think boxing cause performance issues for you.

You should always profile your application and see where is the part that exactly hurts the performance.

So if you are trying to compare two integers then the operation is (a == b). If you write a function for this then an additional function call is needed. If you add additional generic methods, anonymous types, boxing, unboxing ... then all of these additional operation will decrease performance.

as mentioned here you can prevent boxing of integers.

and here is a benchmark

private static void Main(string[] args)
{
    var sw1 = new Stopwatch();
    bool b1 = true;
    sw1.Start();
    for (int i = 0; i < 10 * 1000 * 1000; i++)
    {
        b1 = b1 ^ AreEqual(i, i + 1);
    }
    sw1.Stop();
    Console.WriteLine(b1);
    Console.WriteLine(sw1.ElapsedTicks);


    var sw2 = new Stopwatch();
    bool b2 = true;
    sw2.Start();
    for (int i = 0; i < 10 * 1000 * 1000; i++)
    {
        b2 = b2 ^ AreEqualEx(i, i + 1);
    }
    sw2.Stop();
    Console.WriteLine(b2);
    Console.WriteLine(sw2.ElapsedTicks);
}

public static bool AreEqual<T>(T a, T b)
{
    return a.Equals(b);
}

public static bool AreEqualEx<T>(T a, T b) where T:IEquatable<T>
{
    return a.Equals(b);
}

and the result is

True
254379
True
35514

Community
  • 1
  • 1
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74