none
Memory usage RRS feed

  • Question

  • I have a program that takes about 150M of memory. I'd like to reduce that. I ran the performance monitor (working set - private) and it is at 161,464,320 and task manager is at 157,680K. If I keep clicking around it can get past 200M.

    If I seperate out the program into smaller exes, I'm imagining I can reduce the loaded capabilities.

    I was wondering if I removed the xaml portion and just used the "code behind" to create the views if that would reduce the load, but how to you clear and reload it?
    Monday, April 6, 2009 8:17 PM

Answers

  • I've seen this problem many times during development of many WPF projects. If there is not apparent reason for memory leaks then the best solution so far is to force GC to collect memory. For example in your applicatoion you may run following MemoryCareService.

    public static class MemoryCareService
        {
            private static System.Timers.Timer _timerMemoryCare;
    
            public static void Start()
            {
                _timerMemoryCare = new System.Timers.Timer(5000);
                _timerMemoryCare.Elapsed += new System.Timers.ElapsedEventHandler(MemoryCareService.TimerMemoryCare_Elapsed);
                _timerMemoryCare.Enabled = true;
            }
    
            public static void Stop()
            {
                if (_timerMemoryCare != null)
                {
                    _timerMemoryCare.Enabled = false;
                    _timerMemoryCare.Dispose();
                    _timerMemoryCare = null;
                }
            }
    
            public static void TimerMemoryCare_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                MemoryCareService.MinimizeMemoryUsage();
            }
    
            [DllImport("kernel32.dll")]
            public static extern bool SetProcessWorkingSetSize(IntPtr aProcess, int aMinimum, int aMaximum);
    
            private static void MinimizeMemoryUsage()
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    MemoryCareService.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
            }
        }
    

    The worsest thing will occur when your application eats all RAM, then all system become extremely slow, especially on old computers. I just recommend to run such service on all .Net applications which actively work with memory.

    Regards,
    • Marked as answer by a2BWell Wednesday, April 8, 2009 1:37 PM
    Tuesday, April 7, 2009 7:27 PM

All replies

  • If you removed the xaml portion and just used the "code-behind" then there would be no need for you to even use WPF. You can then code your application using Winforms. Can you please post some code for where you see the application hogging memory and we can help you in more detail.
    Monday, April 6, 2009 9:06 PM
  • I guess, what would you want to see? I have one program that has over 150 dlls attached to it. Of those dll, they are reusing dlls over and over again. I can't say how many links there are, but I know there are quite a few.
    Tuesday, April 7, 2009 1:01 PM
  • Are unit tests a possibility? (As far as having 150dlls... that would explain the memory hog.)
    Tuesday, April 7, 2009 2:01 PM
  • What would be a good unit test?

    Tuesday, April 7, 2009 2:43 PM
  • Well it would depend on your program. If you really have 150 dlls then it would really be a pain to troubleshoot. Do you really have 150 projects? (1 for each DLL?)
    Tuesday, April 7, 2009 2:49 PM
  • Yeah, we have that many projects. One project can contain multiple instances of another project too.
    Tuesday, April 7, 2009 4:10 PM
  • In this case one of the ways that you can decrease the amount of memory usage is to be very stingy about which DLLs get loaded into memory. Make it a rule - if a user does not see it on the screen then it shouldn't be loaded into memory. (Unless it's a cache or a background process of some sort)

    Also, if it's a client/server app then moving some or all business logic on the server side will help make it a thin-client. Or at-least a thinner client :) 
    Tuesday, April 7, 2009 4:56 PM
  • how do you do this:
    In this case one of the ways that you can decrease the amount of memory usage is to be very stingy about which DLLs get loaded into memory. Make it a rule - if a user does not see it on the screen then it shouldn't be loaded into memory. (Unless it's a cache or a background process of some sort)
    Tuesday, April 7, 2009 5:53 PM
  • Sorry but that depends entirely on the architecture used in your project. Does the project follow any design patterns like MVVM or MVC? 

    Also, I've noticed that using ElementHost causes a spike in memory. Are you using any interop with winforms?
    Tuesday, April 7, 2009 5:56 PM
  • We use more of a MVC.

    You lost me on the ElementHost thing. I can say that we have one window and the rest are usercontrols. We don't have any winforms per say. Might have one. old C# progam that we are linking to.
    Tuesday, April 7, 2009 6:18 PM
  • I've seen this problem many times during development of many WPF projects. If there is not apparent reason for memory leaks then the best solution so far is to force GC to collect memory. For example in your applicatoion you may run following MemoryCareService.

    public static class MemoryCareService
        {
            private static System.Timers.Timer _timerMemoryCare;
    
            public static void Start()
            {
                _timerMemoryCare = new System.Timers.Timer(5000);
                _timerMemoryCare.Elapsed += new System.Timers.ElapsedEventHandler(MemoryCareService.TimerMemoryCare_Elapsed);
                _timerMemoryCare.Enabled = true;
            }
    
            public static void Stop()
            {
                if (_timerMemoryCare != null)
                {
                    _timerMemoryCare.Enabled = false;
                    _timerMemoryCare.Dispose();
                    _timerMemoryCare = null;
                }
            }
    
            public static void TimerMemoryCare_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                MemoryCareService.MinimizeMemoryUsage();
            }
    
            [DllImport("kernel32.dll")]
            public static extern bool SetProcessWorkingSetSize(IntPtr aProcess, int aMinimum, int aMaximum);
    
            private static void MinimizeMemoryUsage()
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    MemoryCareService.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
            }
        }
    

    The worsest thing will occur when your application eats all RAM, then all system become extremely slow, especially on old computers. I just recommend to run such service on all .Net applications which actively work with memory.

    Regards,
    • Marked as answer by a2BWell Wednesday, April 8, 2009 1:37 PM
    Tuesday, April 7, 2009 7:27 PM
  • a2BWell,

    ElementHost is used if you would like to display a WPF UserControl in a Windows UserControl or Winform.

    When I mention that you only load the DLLs required to show the user something I mean this:

    Let's say I have a form with a TabControl. Each tab has a UserControl. If the controls are there sitting in the xaml then everytime I open this form, it has to render the TabControl and all the UserControls associated with it. (Even though the user may never even click outside the active tab)

    Now if I was smart about it and followed my rule (if a user does not see it on the screen then it shouldn't be loaded into memory.) then I can load my UserControls on-demand. So  when my user comes to the TabControl I am initally only loading the UserControl that the user is seeing. Then as the user clicks on another tab I load in the next UserControl.
    Tuesday, April 7, 2009 8:38 PM
  • I'll do some research on ElementHost. I don't know how to do anything like that in code. The code from Ivan worked and brought it down. It keeps spiking though, so I would like to know a better way. We did remove the stop, it didn't seem to be called. We do have a workaround though.

    Thanks.
    Wednesday, April 8, 2009 1:39 PM