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:
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>