none
WinForms .NET 3.5 - weird problem with big memory usage. RRS feed

  • Question

  • Hi

    I have WinForms application .NET 3.5. I run this application on W7 x64 with 4GB RAM, I have 2 CPU cores.
    Yesterday after 7 hours of working my app I observed big problem with memory usage.
    Usually my app uses about 300 MB but in this case it was about 3.5GB and CPU usage was 50% (so one core was 100%).

    I run perfmon and I checked some counters:
       
    private bytes 3.5 GB
    LOH 45MB,
    bytes in all heaps 3.2 GB
    gen0 207MB, gen1 13MB, gen2 2MB
    GC Handles 30 MB
    Induced GC 18 MB
    total reserved bytes 3.3 GB
    total committed bytes 3.2 GB
    pinned objects 125KB
    sink blocks in use 56 MB
    CPU 2 cores, 50 % (100% one core)

    Why total reserved bytes and total committed bytes are so big?? I am really surprised and I do not see any explanation. Does anybody have some idea?

    I build my app with switch “Any CPU” on WinXP  x86 so I think under W7 x64 it works on wow64 emulator. Maybe it can be the reason of this problem?


    Regards

    Friday, February 18, 2011 5:36 PM

Answers

  • On W7, x64, it's running as a native 64bit application (since you had AnyCPU on).  Without this, it would have thrown an OutOfMemoryException before this could have ever occurred (usually around 1.2-1.6GB of ram usage).

     

    Looking at your counter information, it looks like you have a memory leak somewhere in your application.  Even with the GC, this can still happen.

     

    This most commonly happens if you have a long lived object (such as your main form, or a static class) exposing an event, and you have lots of things subscribing to the event.  For example, if you open forms that subscribe to an event on your main form, then later close them without unsubscribing from the event, it will prevent the GC from ever cleaning up the memory associated with that form.

     

    You could use SOS to debug this - as it will let you see exactly which objects are taking up that 3.2GB of committed space.

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by kicaj Sunday, February 27, 2011 10:51 AM
    Friday, February 18, 2011 9:22 PM
    Moderator
  • There is something missing. You have 3.2 GB in all Heaps but the GB memory leak does not show up in Gen 0,1,2, LOH. But you seem to have allocated a lot of sync blocks. Just a guess are you reading many different xml files in your application which leads to XmlSerializer assemblies loaded into memory which are never unloaded? It could be that your loader heap the the heap which consumes that much memory. This would indicate a dynamic code generation problem where some assembly is created and loaded into the process again and again. Yours, Alois Kraus
    • Marked as answer by kicaj Sunday, February 27, 2011 10:51 AM
    Friday, February 18, 2011 10:56 PM
  • In any case to get to the issue you will have to use Windbg and SOS to find out what is going on. If you use .NET 3.5 you could use psscor2 .dll which is more powerful.

    The simplest set of commands would be. Start Windbg and attach to the process when your app consumes so much memory. Then type the following commands into the Windbg window

    .loadby sos mscorwks

    !DumpHeap -stat

    !eeheap -gc

    !eeheap -loader

    !SyncBlk

    !DumpDomain

    From this data it would be possible to drill deeper what is going on.

     

    Yours,

      Alois Kraus

     

    • Marked as answer by kicaj Sunday, February 27, 2011 10:52 AM
    Sunday, February 20, 2011 6:07 PM

All replies

  • On W7, x64, it's running as a native 64bit application (since you had AnyCPU on).  Without this, it would have thrown an OutOfMemoryException before this could have ever occurred (usually around 1.2-1.6GB of ram usage).

     

    Looking at your counter information, it looks like you have a memory leak somewhere in your application.  Even with the GC, this can still happen.

     

    This most commonly happens if you have a long lived object (such as your main form, or a static class) exposing an event, and you have lots of things subscribing to the event.  For example, if you open forms that subscribe to an event on your main form, then later close them without unsubscribing from the event, it will prevent the GC from ever cleaning up the memory associated with that form.

     

    You could use SOS to debug this - as it will let you see exactly which objects are taking up that 3.2GB of committed space.

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by kicaj Sunday, February 27, 2011 10:51 AM
    Friday, February 18, 2011 9:22 PM
    Moderator
  • There is something missing. You have 3.2 GB in all Heaps but the GB memory leak does not show up in Gen 0,1,2, LOH. But you seem to have allocated a lot of sync blocks. Just a guess are you reading many different xml files in your application which leads to XmlSerializer assemblies loaded into memory which are never unloaded? It could be that your loader heap the the heap which consumes that much memory. This would indicate a dynamic code generation problem where some assembly is created and loaded into the process again and again. Yours, Alois Kraus
    • Marked as answer by kicaj Sunday, February 27, 2011 10:51 AM
    Friday, February 18, 2011 10:56 PM
  • 56MB for “sink blocks in use” – is it big value? I have not had to care about this counter in my applications – till now.
    Why are you guessing that the problem is with XmlSerializer and dynamic code generation?
    I use some external library that might use XmlSerializer and dynamic code generation – e.g. for saving and retrieving columns settings from grids in my application.

    Counter “sink blocks in use” is somehow related with XmlSerializer and dynamic code generation?

    I still do know why total reserved/committed bytes are so big and LOH, gen0, gen1, gen2 are so small.

    Regards

    kicaj
    Saturday, February 19, 2011 12:39 PM
  • 56mb is a big value.  The fact that you're using 3.2gb of memory, but almost no managed memory suggests that you have some native wrapper API that's not being released appropriate, and is leaking memory.

    This could be XmlSerializer handles - but frankly, could be any other API that wraps native allocations.  Your 3rd party libs may be responsible, or COM, or anything else.  Look for something that is not being disposed, or is subscribing to an event on a long lived object (ie: a static class, a "main window" etc) that isn't being unsubscribed.  Those are the most common sources of memory leaks in .NET.

     

    Again - SoS could potentially help here, as it could show you what has so many handles open that aren't being collected.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Sunday, February 20, 2011 1:05 AM
    Moderator
  • In any case to get to the issue you will have to use Windbg and SOS to find out what is going on. If you use .NET 3.5 you could use psscor2 .dll which is more powerful.

    The simplest set of commands would be. Start Windbg and attach to the process when your app consumes so much memory. Then type the following commands into the Windbg window

    .loadby sos mscorwks

    !DumpHeap -stat

    !eeheap -gc

    !eeheap -loader

    !SyncBlk

    !DumpDomain

    From this data it would be possible to drill deeper what is going on.

     

    Yours,

      Alois Kraus

     

    • Marked as answer by kicaj Sunday, February 27, 2011 10:52 AM
    Sunday, February 20, 2011 6:07 PM
  • I checked XmlSerializer class and I see that when I create new instance of XmlSerializer some new dll with random name is loaded to current domain (Visual Studio -> Debug -> Windows -> Modules).

    When this dll is unloaded? In my case it looks that this dll is never unloaded.

    I think that if I had a lot of instances of XmlSerializer for different types I would have a lot if dlls loaded into current domain – so maybe it would the reason of this problem. Am I correct?

    Regards


    kicaj
    Tuesday, February 22, 2011 8:06 AM
  • Yes, and no.  It will load lots of dynamically generated assemblies - but it would take a LOT of them to use up >3gb of RAM.  I doubt that (alone) is the issue.

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, February 22, 2011 3:36 PM
    Moderator
  • Another tool that is very helpful in finding out what is going on with memory is the CLR Profiler. It will profile .NET 3.5 programs, but you will need to install .NET 4. The download of the CLR Profiler includes excellent instructions and examples.
    Just because the code works, doesn't mean it is good code.
    Tuesday, February 22, 2011 3:48 PM