3

Question:

What is the performance and memory overhead of using an array with the length of 1 instead of the value directly?

private Item[] item = new Item[1];
   vs.
private Item item;

Usage:

I have an abstract base class ItemHolder which is beeing inherited both by the SingleItemHolder and MultipleItemHolder classes. The first holding a single item as the main value while the other holds a list. To access the value I see three possibilities:

Adding two methods to the base class

public abstract Item GetItem();
public abstract Item[] GetItems(int amount);

drawback beeing the SingleItemHolder has the unnecessary method to get multiple items while having only one per definition.
Another method would be to only implement the second method and passing the single value as a length 1 array

public override Item[] GetItems()
{
    return new[] { storedItem };
}

or storing the single value as a length 1 array in the first place

private Item[] item = new Item[1];
public override Item[] GetItems()
{
    return item;
}

Both the multiple as well as the single item holders are used equally as often and quite often in general. The methods in question could very well be called dozends of times per game frame from all over the gameworld. Therefor I am wondering which version the most efficient would be, or, to be more general, what difference in overhead a length 1 array has over a single value.

4
  • 1
    It might be worth noting that arrays themselves are objects in C#, so this may or may not have a minute impact on overhead: learn.microsoft.com/en-us/dotnet/csharp/programming-guide/… Commented May 3, 2020 at 2:01
  • 1
    Also, if Item is a struct, then adding another pointer to this adds a small amount of overhead. If you are looking to avoid returning a value type (such as a struct), look into ref returns: learn.microsoft.com/en-us/dotnet/csharp/programming-guide/… Commented May 3, 2020 at 2:02
  • 1
    Sadly, Item is a class as of now. Regardless, there are some really interessting uses of ref I didn't know about, thank you. Commented May 3, 2020 at 2:12
  • Also, the array overhead resulting in it beeing an object itself is an interesting observation I overlooked, thank you for this too Commented May 3, 2020 at 2:13

2 Answers 2

2

Just a short note. In the .NET world the big performance issue is the GC that may easily lock the app for 50-100ms. You will likely not see a big difference in reading data from an object or single value array. But you will likely get a penalty if you need to create such object a lot. You certainty should avoid creating objects from the getters code.

I think that this article may be helpful: https://michaelscodingspot.com/avoid-gc-pressure/. Also consider usage of some Profile tool to check how much time it actually takes. I prefer using the PerfView provided by MS. It may take some time to start using it, but you certainly get benefits in results.

Sign up to request clarification or add additional context in comments.

2 Comments

Interesting take, thank you. Do you habe a link where I can learn about this locking in more detail?
I think that this article may be helpful: michaelscodingspot.com/avoid-gc-pressure. Also consider usage of some Profile tool to check how much time it actually takes. I prefer using the PerfView provided by MS. It may take some time to start using it, but you certainly get benefits in results.
1

What is the performance and memory overhead of using an array with the length of 1 instead of the value directly?

That depends entirely on how compiler Optimisations, JiT compiler and Index accessor pruning feel about that array today. At it's core, everything is a pointer. The process does not care if it points to a function, a single int or the beginning of a int array. Aside from the jump into the Indexer function and maybe the Indexer sanity checks, there should be no performance impact. And even that one Indexer access could pruned, or at least inlined.

It is theoretically possible that the optimsations see your new int[1] and decide a basic int would do there. The JiT could even do that if the size is only defined at runtime. However, this is rather unlikely.

If you need a array there, you need a array there. The odd case that it is sometimes 1, is nothing to worry about. Even if the size 1 array is somehow common, having a path with a basic int would be a micro-optimisation. It would just fall under the speed rant: https://ericlippert.com/2012/12/17/performance-rant/

If you have two function overloads - one taking a int and one taking a int[] - you should propably only code out the int[] version. It is pretty trivial to chain the int version to call the array version.

5 Comments

"The odd case that it is sometimes 1, is nothing to worry about" My uneasiness stems from the fact that around half the ItemHolders will have a length 1 array, so hundreds in total. Regardless, I'm a bit disappointed the overhead can't be determined further and in more detail
@harlekintiger Again, read the speed rant. The difference is very small, even if no optimisation picks it up. Most likely even pointlessly small. It will likely not mater that you do array access* on hundreds of elements. But that you do array access on **hundreds of elements. | If there is any serious performance impact, it is the sheer amount of things that need processing. Not if it takes 110 or 100 CPU cycles to process one of them.
@harlekintiger Note that if you actually do need that difference, you are deep in Realtime Programming territory. And if that is the case, using C#/.NET to begin with was a bad idea. A Runtime with GC Memory management and JiT compilers is not the right environment to start any realtime programming projects.
Seeing that all solutions I thought of are basically O(n), I have to admit the difference in performance will not be noticable. The reason I asked was 50% out of curiosity about the implementation details under the hood, and 50% the desire to know the best practice for such a task
@harlekintiger Best Practice? Write a programm that works. If it is fast enough, you are done. If it is not fast enough? You will need to find a horse that is fast enough. And this one will only be slightly faster, so likely not fast enough. If you need that kind of speed, Multitreading might be worth a look.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.