Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Minimize to Tray AND Minimize required resources

I have a WinForms application (I'm using VB) that can be minimized to the system tray. I used the "hackish" methods described in multiple posts utilizing a NotifyIcon and playing with the Form_Resize event.

This all works fine aesthetically, but the resources and memory used are unaffected. I want to be able to minimize resources when minimizing to system tray, just like Visual Studio does. If you are coding in Visual Studio, the memory usage can creep up (depending on project size) to above 500 MB, but when minimizing Visual Studio to the taskbar, the memory drastically decreases to (what I'm assuming) is the minimal amount.

Does anyone have any clue as to how to accomplish this?

Here's a short description of the application, if anyone finds it relevant: I have a windows form with a ListView that contains Work Orders for my IT department. The application has a "listener" that notifies when a new Work order is submitted. So, when the application is running in the system tray, all I really do is compare the count of items in the ListView to a count of rows in a SQL table every couple of minutes.

EDIT: To be more specific, a windows form intrinsically has threads and resources being used by means of the controls, when the form is invisible (in the system tray) these resources are still being used. What can I do to minimize these resources, short of killing all the controls and redrawing them when the form is restored.

like image 934
Joey Avatar asked Nov 04 '08 20:11

Joey


3 Answers

Calling MiniMizeMemory() will do a garbage collection, trim the process working size, then compact the process' heap.

public static void MinimizeMemory()
{
    GC.Collect(GC.MaxGeneration);
    GC.WaitForPendingFinalizers();
    SetProcessWorkingSetSize(
        Process.GetCurrentProcess().Handle,
        (UIntPtr)0xFFFFFFFF,
        (UIntPtr)0xFFFFFFFF);

    IntPtr heap = GetProcessHeap();

    if (HeapLock(heap))
    {
        try
        {
            if (HeapCompact(heap, 0) == 0)
            {
                // error condition ignored
            }
        }
        finally
        {
            HeapUnlock(heap);
        }
    }
}

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetProcessWorkingSetSize(
    IntPtr process,
    UIntPtr minimumWorkingSetSize,
    UIntPtr maximumWorkingSetSize);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcessHeap();

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool HeapLock(IntPtr heap);

[DllImport("kernel32.dll")]
internal static extern uint HeapCompact(IntPtr heap, uint flags);

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool HeapUnlock(IntPtr heap);
like image 189
Jesse C. Slicer Avatar answered Nov 10 '22 05:11

Jesse C. Slicer


You're probably looking for this function call: SetProcessWorkingSetSize

If you execute the API call SetProcessWorkingSetSize with -1 as an argument, then Windows will trim the working set immediately.

However, if most of the memory is still being held by resources you haven't released minimizing the working set will do nothing. This combined with the suggestion of forcing Garbage Collection might be your best bet.

From your application description, you might want to also verify how much memory the ListView is consuming as well as the database access objects. I'm also not clear on how you're making those monitoring database calls. You might want to isolate that into a separate object and avoid touching any of the forms while minimized, otherwise the program will be forced to keep the controls loaded and accessible. You could start a separate thread for monitoring, and pass the ListView.Count as a parameter.

Some sources:

.NET Applications and the Working Set

How much memory does my .Net Application use?

like image 28
Esteban Brenes Avatar answered Nov 10 '22 03:11

Esteban Brenes


To clean up unused memory, use GC.Collect()... though you should read up on why to do it and why its usually a bad idea to use it often.

If you mean other resources, you will need to be more specific.

like image 2
StingyJack Avatar answered Nov 10 '22 03:11

StingyJack