0

My C# application is caching images from file in RAM so that it can display it to users faster (30-60 FPS).

They're being stored in Bitmap objects.

After around 200 images, it throws a "System.OutOfMemoryException".

I tried using

System.Diagnostics.PerformanceCounter("Memory", "Available MBytes");

To see what the ceiling is and to try and stay under it, but the value it returns doesn't seem to match accurately.

For example. If I run it normally it starts with 1,500 MB available and it throws the exception around 300 MB.

However, if I start a big application like After Effects and make it use a lot of my ram.

Then my application starts at 300, does around 200 images, then throws the exception around 40 MB, but only after it already reaches 0 MB and bounces back up for some reason.

How can I find out how much RAM is actually available to my C# application so that I can know the exact number of images I can cache for playback without going anywhere near the current PC's ceiling and risk exceptions?

John
  • 5,942
  • 3
  • 42
  • 79
  • Are you sure that this is not caused by some other problem? Like not correctly disposing of your images? – Steve Aug 06 '18 at 16:07
  • @Steve the images are not being disposed because I want them in RAM for faster playback. So the question is, how can I calculate how many images are available for caching. – John Aug 06 '18 at 16:09

1 Answers1

0

Short answer: Use GlobalMemoryStatusEx Win32 API's ullAvailPageFile

More details:

System.Diagnostics.PerformanceCounter("Memory", "Available MBytes");

The above gives the "Physical memory"

https://blogs.msdn.microsoft.com/faber/2014/11/20/tracking-windows-performance-counters-by-application/

This measures the amount of physical memory, in megabytes, available for running processes.

There is always "Virtual Memory" in your machine and it is likely to be configured with the "Page File"

The appropriate measure that a program could use is: Available Page File

https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx

ullAvailPageFile

The maximum amount of memory the current process can commit, in bytes. This value is equal to or smaller than the system-wide available commit value.

I can't find a Managed library call to get this info. So, an available option to to directly call the Win32 API using pinvoke.

https://www.pinvoke.net/default.aspx/kernel32.GlobalMemoryStatusEx

 [return: MarshalAs(UnmanagedType.Bool)]
 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 static extern bool GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer);

In my local testing, I see that if the Available Page Size is less than 1 GB, the program can start to fail with "Out of memory" exception anytime.

Note this value is not a fixed value, it would change as your program / other program runs in the system. My understanding is that the as you allocate memory, the "Page File" grows (till its configured limit).

You may want to built your application as "64 bit" application to use more memory.

  1. http://blogs.microsoft.co.il/sasha/2012/04/04/what-anycpu-really-means-as-of-net-45-and-visual-studio-11/
  2. .net console app 32 vs 64 bit

For the Console App, make it 'Any CPU' and clear the 'Prefer 32-bit' check box

Page file settings

There are extensive info on the appropriate Page File size. In most simple cases, it is set as a multiple of available RAM.

https://support.microsoft.com/en-in/help/2860880/how-to-determine-the-appropriate-page-file-size-for-64-bit-versions-of

Windows 8.1 and Windows Server 2012 R2

Maximum page file size

3 × RAM or 4 GB, whichever is larger.

Community
  • 1
  • 1
Subbu
  • 2,130
  • 1
  • 19
  • 28