How to use IDisposable to fix memory leaks

I have a .net application that seems to have a memory leak problem. The .net service starts about 100 MB of memory, but under load it reaches about 400-500 MB. Most of my classes do not have unmanaged resources, but those that already implement IDisposable. So my question is, what would the slapping IDisposable in my classes help?

4-500 MB does not per se. Anxiety 8 different services. Each of them is built using SharpArch, NServiceBus, Windsor and NHibernate. I feel that one of them has something that is causing the problem. My concern is that the total memory of all services ranges from 3.2 to 3.6 gigabytes of memory from 4 concerts. It does not yet throw OutOfMemory exceptions, but I would like to head this on the pass. I also used dotTrace, which give me some information, I'm just not sure how to act on this information.

+6
garbage-collection c #
source share
5 answers

My first concern was to make sure that you are measuring something important. β€œMemory” can mean many different things. There is a huge difference between running out of virtual memory space and running out of RAM. There is a huge difference between a performance problem caused by shredding a page file and a performance problem caused by creating too much pressure in the GC.

If you don’t understand the relationship between RAM, virtual memory, working set, and the page file, start by reading until you understand all of this. The way you formulated this question makes me suspect that you think that virtual memory and random access memory are the same thing. They, of course, are not.

I suspect the arithmetic you are doing is:

  • I have eight processes, each of which consumes 500 million bytes of virtual address space.
  • I have 4 billion bytes of RAM
  • So I'm going to get an OutOfMemory exception

This syllogism is completely invalid. This is a syllogism:

  • I have eight quarts of ice cream
  • I have room for nine quarts of ice cream in the freezer
  • Therefore, if I get two more quarts of ice cream, something will melt.

when in fact you have a whole warehouse cold store next door. Remember that RAM is just a quick way to store things near it, like your refrigerator. If you have more things to keep, who cares if you run out of place? You can always appear next door and place material that you use less often in deep freeze mode - the page file. This is less convenient, but nothing melts.

You get an "out of memory" exception when a process expires from the virtual address space, and not when all the RAM in the system is consumed. When all RAM in the system is consumed, you do not get an error, you get crap performance because the operating system spends all its time working with the disk.

So, anyway, start by understanding what you are measuring and how memory works in Windows. In fact, you should look for:

  • Is any process a threat to use more than two billion bytes of virtual memory on a 32-bit system? The process receives only 2 GB of virtual memory (and not RAM, remember that virtual memory has nothing to do with RAM: therefore its called "virtual" is not hardware ) on win32, which is addressed by the user code; you will get OOM if you try to use more.

  • Is there any process that may arise when trying to allocate a huge block of virtual memory so that there is no continuous block of this size? For example, are you likely to allocate ten million bytes of data in one array? Again, OOM.

  • Is the working set - that is, the pages of the virtual memory of a process * that should be in RAM for performance reasons - all processes that are smaller than the amount of RAM? If not, soon you will beat, but not OOM.

  • Is your page file large enough to handle pages of virtual memory that can be unloaded to disk if RAM starts to shrink?

So far, none of this has anything to do with .NET. Once you have actually determined that there is a real problem - maybe not so - then start an investigation based on the real problem. Use the memory profiler to verify what the memory allocator and garbage collector do. See if there are huge blocks in a large heap of an object or unexpectedly large graphs of living objects that cannot be assembled, or what. But use good engineering principles: understand the system, use tools to study actual empirical characteristics, experiment with changes and carefully evaluate their results. Do not start randomly spanking magic IDisposable interfaces on several classes and hope that this will make the problem - if there is one - go away.

+17
source share

If all classes for which unmanaged resources implement IDisposable and are deleted correctly (using or try / finally), then adding additional implementations of IDisposable will not help.

The first problem is that you do not know why you are leaking. Managed applications typically leak for one of the following reasons.

  • Misuse of unmanaged resources
  • Retention on large object graphs of managed objects

Given the information in your question, this is almost certainly # 2 what causes the problem. You will need to get a profiler or windbg to tell you what the actual leak is and what root objects cause this.

Here is a great Rico article to get you started.

+15
source share

Answer: almost certainly not. Have you confirmed that you are actually holding memory, which should not be, by profiling your service?

Keep in mind that the garbage collector may not necessarily release memory until it is needed, so it may not be unusual for it to hit 400-500 mb. The point at which I began to worry would be when, after [using a reasonable amount of time here] use, it crept further and reached 1Gb, even if it was not under any higher load level.

+5
source share

Short answer: None.

Longer answer: Noooooo.

I think you already knew that - if you hadn’t done this, you would not have a β€œslap” IDisposable on classes that really needed it - IDisposable has nothing to do with GC. The only thing that really matters here is that you applied Finalizer (~ classname) to your objects unnecessarily - this will cause them to be copied in the single-threaded finalizer queue before they get GC'd, regardless of what they are contain unmanaged resources or not.

+4
source share

Measurement, measurement, measurement

If you want to reduce memory usage for your application, you first need to determine where it is used.

You can get a rough idea by adding a few perfmon counters to "private bytes in all heaps, bytes in a bunch of large objects, gen 1, gen 2", etc.

If you determine that you are using too much managed memory. You can opt out of using a tool such as . Clean memory profiler or very flexible, but windbg + sos

Once you isolate the place where your memory goes, you can look at strategies for reducing usage, it can be something as simple as replacing the Dictionary with a cache or adding a string builder.

A solution very unlikely to sprinkle IDisposable on everything.

+2
source share

All Articles