8

I have a mutable class which has a private List<T> field inside. In the Reset() method of my class, should I clear the list using its Clear() method or just assign its field a new list? Note that the list is not public and is only used by the class itself. So assigning a new list should make the old one unreachable. Since the Clear() method is an O(n) operation, I wonder what is the downside of just assigning a new list over it.

Şafak Gür
  • 7,045
  • 5
  • 59
  • 96

3 Answers3

7

The only downside I can think of is if you need to use the list again you'll have to allocate new space for it.

Nulling it will just make the list and its content (assuming no other references) eligible for GC. Clearing it would remove the items but leave the memory allocated.

Personally I tend to null the thing as even if I need it again, the size will have changed completely.

Update: Pertaining to the comments below, you state these objects will be managed in a pool of objects. I would advise creating a small profiling console app to get the final answer. The discussion is now stepping into the specifics of your implementation and the intended usage of the object pool, which could easily change the answer.

Generally speaking, if you have lists that don't change in length much and are always going to be required, I would use Clear to avoid allocating new memory for the lists. If the list length is liable to a lot of change, or usage is sometimes sparse - I would favour nulling it in order to reclaim memory and gain some minor benefits via lazy instantiation of the lists.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • So if I have a list of bytes with 2k bytes in it, which would be faster? Me, calling Clear or GC, doing reallocation? I ask this because I have about 1-2k of objects with these lists inside, so I want to be sure which would be better, performance-wise. – Şafak Gür Jul 30 '12 at 08:10
  • @d4wn Personally I wouldn't worry about performance until you can prove it's a problem. It depends on what you want to do with the list. If the items are no longer needed, but you are likely to need the list size or want to avoid re-allocation of memory for list growth, I'd `Clear`. If you don't care about the list afterwards or it might shrink a lot, I'd `list = null; list = new List()`. In either situation the GC will collect x-many objects so it doesn't matter. Any potential performance differences will be the difference between O(n) iteration vs list growth re-allocation. – Adam Houldsworth Jul 30 '12 at 08:16
  • So, one more question: Why would I want to "avoid re-allocation of memory for list growth"? I use a pool for these objects, they're going to be reused over and over again as long as the application is running. Doing re-allocation every time sounds expensive but I don't know that much about GC and how much this process can effect the performance. – Şafak Gür Jul 30 '12 at 08:23
  • If you are pooling lists of pre-sized `List` then I would favour `Clear` as it expresses the intent more. With pooling you expect the item to be long lived as it returns to the pool. Nulling the list would mean the GC has to reclaim the previous lists memory and then grab the next chunk for the new list. What I mean by allocation is unless you specify the list capacity, it automatically grows when needed. Seeing as though you want to manage a pool I would advise doing your own profiling of nulling vs `Clear` that is specific to your pools requirements. `Stopwatch` helps here. – Adam Houldsworth Jul 30 '12 at 08:25
  • So the pros of using Clear are that it keeps the capacity of the list and avoids re-allocation, and the pros of re-creating it is that this approach provides the benefits of lazy-usage. So if I don't need the list (and that can happen, since the list is a private member of the class I am pooling, I don't pool the lists directly) it is never created. Could you update your post by merging these things you commented before I accept? – Şafak Gür Jul 30 '12 at 08:32
  • This would also make your answer more generic (about the actual question) and less about the specifics of my implementation (the things I asked by commenting). – Şafak Gür Jul 30 '12 at 08:43
0

So then why null it? This will do the trick for you, letting the old list stay on the heap for garbage collection, while existing methods that access the list can continue to function on a new, empty list:

this.FooList = new List<Foo>();
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 1
    I wrote "assigning its field a new list", too. The reason I used the word "nullifying" is because it makes the field unreachable and allows the GC to collect it. But you're right, I should edit the question. Anyway the question was which would be faster and what advantages/disadvantages they have over another. – Şafak Gür Jul 30 '12 at 08:03
  • Nulling it or re-assigning it amount to the same thing in the eyes of the GC. If you null it and re-assign it later, you get a mild benefit of lazy instantiation. – Adam Houldsworth Jul 30 '12 at 08:06
0

After the Reset call I would leave the object in the same state it was in after the constructor had been called.

If your constructor created a new empty List then do that. If not make it null.

ForkandBeard
  • 874
  • 10
  • 28
  • That's what I try to decide. Setting the list once in constructor and use it over and over by clearing it, or create it lazily if needed and set it to null (or to a new list) in Reset. – Şafak Gür Jul 30 '12 at 08:12
  • @d4wn In my opinion I don't think performance should drive this decision. I think making it `null` and lazily loading is the cleanest, I'd do that. – ForkandBeard Jul 30 '12 at 08:21