Home > Net >  Is it better to Clear lists and refill them or simply assign an existing collection to the list?
Is it better to Clear lists and refill them or simply assign an existing collection to the list?

Time:01-18

I'm working on copying/modifying a package for unity (xNode) and I'm at the point where NodePortDictionary is defined.

In OnBeforeSerialize the original author clears both the Key and Value lists and iterates through the dictionary adding the key and value pairs to the lists.

public void OnBeforeSerialize() {
    keys.Clear();
    values.Clear();

    foreach(KeyValuePair<string, NodePort> pair in this) {
        keys.Add(pair.Key);
        values.Add(pair.Value);
    }
}

Is there a reason that it should be done that way over this way?

public void OnBeforeSerialize() {
    keys = Keys.ToList();
    values = Values.ToList();
}

I'm not asking if it's 'a better practice', I'm trying to understand if its better from a performance perspective. More specifically is there enough of a difference in performance to be concerned about?

CodePudding user response:

These questions are relevant only if your lists have thousands or millions of entries, of if your project is extremely time sensitive (like trying to keep under a certain time threshold, which normally happens in C or C ).

In your first code

public void OnBeforeSerialize() {
    keys.Clear();
    values.Clear();

    foreach(KeyValuePair<string, NodePort> pair in this) {
        keys.Add(pair.Key);
        values.Add(pair.Value);
    }
}

Your cycle runs for the length of the list of pairs, which will have O(n). In the second code

public void OnBeforeSerialize() {
    keys = Keys.ToList();
    values = Values.ToList();
}

the .ToList() run for the length of the list of pairs, and you have two of them, so you will run in O(2n). But O(n)=O(2n), so unless you have millions of entries, you won't see a big difference.

Now in terms of memory allocation, it is better to clean the variables and re-use them because of memory swap. There are concepts called Memory Heap and Memory Stack, where one is accessed faster than the other one. There are limits in how much you can keep on stack, and its not a lot. (Homework: check in which memory you create local variables, global variables, and where the variables can be resized and where they cannot. Also, check if List can be resized, or if it creates a new instance.)

About this:

  1. Right now if both approaches work, it means you haven't exceeded the stack size. Then your second approach will be faster than the first one. The compiler will only assign a new memory address.
  2. If you exceed the stack size, your second approach won't work. You will run into a memory exception. Your only option will be the first approach.
  3. In your example, NodePort and string may not be memory aligned (which means that there is a chance the compiler does bit padding to align to nice lengths, i.e., 64 bits for example). So you should see what the compiler is doing behind the scenes for these variables (you will have to read the assembly code for this, which again, if your project is not time sensitive, its a waste of time).

Visual Studio has excellent profiling tools, so you can play a bit and learn about the memory allocation. Also I suggest to you to read about heap vs. stack, and you will see that there is a lot more of what meets the eye.

Check these, they might help you:

  1. https://www.guru99.com/stack-vs-heap.html
  2. https://www.c-sharpcorner.com/article/stack-vs-heap-memory-c-sharp/
  • Related