Examine your program's available memory: is it leaking?

 

Sometimes your program wakes up and finds itself running in an environment that might not be as suitable as you’d like.

 

For example, it might be distributed to a user running on a machine with not enough memory, and could be failing. Perhaps the failures occur because the user is running multiple applications on the machine, which take up memory, but your application is unaware.

 

You can call GlobalMemoryStatusEx function to find out how much memory is available to your program.

 

On my 64bit Win7 machine:

 

If the display shows Total Virtual = 2,147,352,576 (0x7ffe0000), around 2 Gigs, then you can increase the memory for your program in a couple ways.

 

Load=72%

Total Physical=8,443,699,200

Avail Physical=2,284,720,128

Total PageFile=16,885,506,048

Avail PageFile=8,927,690,752

Total Virtual =2,147,352,576

Avail Virtual =1,837,015,040

 

When I add the 2 lines to the Post Build event as described here: Out of memory? Easy ways to increase the memory available to your program

 

I get double the memory!

 

Load=72%

Total Physical=8,443,699,200

Avail Physical=2,298,707,968

Total PageFile=16,885,506,048

Avail PageFile=8,943,415,296

Total Virtual =4,294,836,224

Avail Virtual =3,977,121,792

 

 

Try running multiple applications along with yours and watch the effect on these numbers.

 

Now if you want to see if your program leaks either native or managed memory, then monitor “Avail Virtual” at a constant point in your application when you know the memory consumed should be consistent. Perhaps at a main menu or after a task has been completed.

 

If that value over time trends upwards, it could be a leak.

Keep in mind there are “intentional” leaks:

1. Undo: you can type a lot in an editor, but you can undo: make sure the undo isn’t clouding your memory monitoring by either taking it out of the picture (disable Undo) or monitor memory at a point where the Undo has been discarded (file is closed)

2. Caches: there can be all sorts of caches, so make sure your application activity has filled the caches. For example, Visual Studio keeps the last N filenames opened. If you go past N, then the cache is filled.

3. Garbage Collection in managed memory. This might introduce some noise, but over time, the monitoring should not be trending up. Besides, both native and managed allocations are small compared to the minimum Virtual Alloc granularity size of 64K: both these heaps grow in large chunks.

4.

 

Leaks can be devastating to performance: less memory available means more time. Managed leaks are often event handlers

 

 

See also:

Examine .Net Memory Leaks

What is your computer doing with all that memory? Write your own memory browser

https://blogs.msdn.com/b/calvin_hsia/archive/tags/memory/

 

<Code>

Imports System.Runtime.InteropServices

 

Class MainWindow

 

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

        Try

            Dim memstat = New MEMORYSTATUSEX

          memstat.dwLength = CType(Marshal.SizeOf(GetType(MEMORYSTATUSEX)), UInt32)

            Dim res = GlobalMemoryStatusEx(memstat)

            If Not res Then

                ' Dim err = Marshal.GetLastWin32Error()

                Dim hr = Marshal.GetHRForLastWin32Error()

                Dim ex = Marshal.GetExceptionForHR(hr)

                Throw ex

 

            End If

            Dim sp As New StackPanel With {.Orientation = Orientation.Vertical}

            sp.Children.Add(

              New TextBlock With {

                    .Text = memstat.ToString}

                )

            sp.Children.Add(

                New TextBlock With {

                    .Text = String.Format("Total Physical = {0:n0}", memstat.ullTotalPhys)

            })

            sp.Children.Add(

                New TextBlock With {

                    .Text = String.Format("Total Virtual = {0:n0}", memstat.ullTotalVirtual)

                })

 

            Me.Content = sp

 

        Catch ex As Exception

           Me.Content = ex.ToString

        End Try

    End Sub

    <DllImport("kernel32.dll", SetLastError:=True)>

    Public Shared Function GlobalMemoryStatusEx(

                                      ByRef lpMemoryStatusEx As MEMORYSTATUSEX

      ) As Boolean

 

    End Function

 

End Class

 

 

 

 

<StructLayout(LayoutKind.Sequential)> _

Public Structure MEMORYSTATUSEX

 

    ' Fields

    ''' <summary>

    ''' Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.

    ''' </summary>

    Public dwLength As UInt32

    ''' <summary>

    ''' Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).

    ''' </summary>

    Public dwMemoryLoad As UInt32

    ''' <summary>

    ''' Total size of physical memory, in bytes.

    ''' </summary>

    Public ullTotalPhys As UInt64

    ''' <summary>

    ''' Size of physical memory available, in bytes.

    ''' </summary>

    Public ullAvailPhys As UInt64

    ''' <summary>

    ''' Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead.

    ''' </summary>

    Public ullTotalPageFile As UInt64

    ''' <summary>

    ''' Size of available memory to commit, in bytes. The limit is ullTotalPageFile.

    ''' </summary>

    Public ullAvailPageFile As UInt64

    ''' <summary>

    ''' Total size of the user mode portion of the virtual address space of the calling process, in bytes.

    ''' </summary>

    Public ullTotalVirtual As UInt64

    ''' <summary>

    ''' Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes.

    ''' </summary>

    Public ullAvailVirtual As UInt64

    ''' <summary>

    ''' Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes.

    ''' </summary>

    Public ullAvailExtendedVirtual As UInt64

    Public Overrides Function ToString() As String

        Dim str = String.Format(

            "Load={0}%" + vbCrLf +

            "Total Physical={1:n0}" + vbCrLf +

            "Avail Physical={2:n0}" + vbCrLf +

            "Total PageFile={3:n0}" + vbCrLf +

            "Avail PageFile={4:n0}" + vbCrLf +

            "Total Virtual ={5:n0}" + vbCrLf +

            "Avail Virtual ={6:n0}",

            dwMemoryLoad,

            ullTotalPhys,

            ullAvailPhys,

            ullTotalPageFile,

            ullAvailPageFile,

            ullTotalVirtual,

            ullAvailVirtual

            )

        Return str

    End Function

End Structure

 

 

 

</Code>