5

I have a class that has a byte array holding from 1,048,576 bytes up to 134,217,728 bytes. In the dispose void I have the array set to null and the method calling the dispose calls GC.Collect after that.

If I dispose right away I will get my memory back, but if I wait like 10 hours and dispose, memory usage doesn't change.

8
  • 14
    So far so good. And what is your question? Commented Nov 28, 2011 at 16:49
  • i dont understand why time would cause the memory to not be freed. and if there is a solution to the problem. Commented Nov 28, 2011 at 16:51
  • 6
    @jasonbay13: When memory is used that long, it gets promoted down the generations of garbage collection. When it's in later generations, it tends not to get collected until the system needs it, it's not a leak, per se. Have you tried the Force option on GC.Collect and specify the generations to collect? Commented Nov 28, 2011 at 16:54
  • @jasonbay13: p.s. I don't really recommend forcing GC, let the GC do it's thing. You're holding onto the memory for a long time, so the GC assumes you will continue to do so and checks it much less frequently. Look up generational garbage collection for more details. Commented Nov 28, 2011 at 16:55
  • 4
    You haven't explained why this is a problem. Memory isn't freed right away. OK, so who cares? It will be freed when it needs to be freed. Let the garbage collector do its job. Commented Nov 28, 2011 at 17:07

3 Answers 3

7

Memory usage is based on OS memory allocation. It may be freed immediately, it may not be. This depends on OS utilization, application, etc. You free it in the runtime, but this doesn't mean the OS alway gets it back. I have to think heres a determination based on memory patterns (ie time here) that affects this calculation of when to return it or not. This was addressed here:

Explicitly freeing memory in c#

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

Comments

1

Note: if the memory isn't released, it doesn't automatically means it used. It's up to the CLR whether it's releases chuncks of memory or not, but this memory isn't wasted.

That said, if you want a technical explanation, you'll want to read litterature about the Large Object Heap: http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

Basically, it's a zone of memory where very large objects (more than 85kB) are allocated. It differs from the other zones of memory in that it's never compacted, and thus can become fragmented. I think what happens in your case is:

  • Case 1: you allocate the object and immediately call GC.Collect. The object is allocated at the end of the heap, then freed. The CLR sees a free segment at the end of the heap and releases it to the OS.

  • Case 2: you allocate the object and wait for a while. In the mean time, an other object is allocated in the LOH. Now, your object isn't the last one anymore. Then, when you call GC.Collect, your object is erased, but there's still the other object(s) at the end of the memory segment. So the CLR cannot release the memory to the OS.

Just a guess based on my knowledge of memory management in .NET. I may be completely wrong.

Comments

1

Your findings are not unusual, but it doesn't mean that anything is wrong either. In order to be collected, something must prompt the GC to collect (often an attempted allocation). As a result, you can build an app that consumes a bunch of memory, releases it, and then goes idle. If there is no memory pressure on the machine, and if your app doesn't try to do anything after that, the GC won't fire (because it doesn't need to). Once you get busy, the GC will kick in and do its job. This behavior is very commonly mistaken for a leak.

BTW: Are you using that very large array more than once? If so, you might be better off keeping it around and reusing it. Reason: any object larger than 85,000 bytes is allocated on the Large Object Heap. That heap only gets GC'd on Generation 2 collections. So if you are allocating and reallocating arrays very often, you will be causing a lot of Gen 2 (expensive) collections.

(note: that doesn't mean that there's a hard and fast rule to always reuse large arrays, but if you are doing a lot of allocation/deallocation/allocation of the array, you should measure how much it helps if you re-use).

2 Comments

actually i make instances of the class containing different size arrays, and at random any one could be disposed of.
I see. If you want to really test whether a leak is occuring, you could throw in some test code that just keeps creating and releasing those arrays indefinitely. They will eventually go away. Probably what's happening is that there isn't enough pressure on the system to prompt a Generation 2 collection. Or, it could be as Adam Tuliper says -- the array is being freed, but the memory is not going back to the O/S immediately. Either way, so long as you aren't holding a reference to the array somewhere, it probably is not a real leak.

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.