2

I've written a simple dotnet app that allocates memory. It uses up all the physical memory on the machine and then crashes with an OutOfMemoryException. However my system has a swap file and it is never used by dotnet. Other applications use swap just fine. I have played with the swappiness (60, 100, 1) but this had no effect.

My understanding is that a process on Linux can consume all the physical memory it wants and if there is no memory left that memory will be written to the swap file/partition. Only when the swap and physical memory are both full should an application crash with an OOM. This is what other applications do but not dotnet applications.

I have tried dotnet core 3.1 and 5.0, the OS used was Ubuntu 20.04.

EDIT: my test code:

namespace TestProject
{
    class Program
    {
        static List<byte[]> l = new List<byte[]>();

        static void Main(string[] args)
        {
            while (true)
            {
                var b = new byte[100 * 1000 * 1024];
                l.Add(b);
            }
        }
    }
}
shortspider
  • 1,045
  • 15
  • 34
  • Similar question for Java - https://stackoverflow.com/questions/64888598/make-java-understand-that-swap-exists-and-encourage-him-to-use-it . Not quite a dupe (and its flagged for quality) but the answer starts to touch on how the OS uses swap to grant more memory to applications – Freiheit Jan 20 '21 at 22:03
  • This is configurable behavior on Linux. What is your `vm.overcommit_memory` set to? Is the .net app running in 64bit mode? Are you creating any 2GB+ arrays? – that other guy Jan 20 '21 at 22:04
  • 2
    Programs don't know anything about swap, it's an OS thing that's managed by the kernel. How are you allocating memory? Can you show the relevant code? – Alejandro Jan 20 '21 at 22:08
  • @thatotherguy `cat /proc/sys/vm/overcommit_memory` returns a result of 0. It is a 64 bit application and I am creating 100MB arrays. – shortspider Jan 22 '21 at 16:38
  • @Alejandro test code added. I know it will allocate memory forever but I would expect it to at some point use swap and only crash when both physical memory and swap runs out. I understand that processes just ask for memory and the OS gives it, which is why I can't understand why this program gets no swap (OOM exception when physical memory is used up) but if I open enough chrome tabs it will use swap. – shortspider Jan 22 '21 at 16:42
  • @shortspider Is your application running inside docker? – Vikram Singh Saini Jan 26 '21 at 02:20
  • @Vikram it is not. – shortspider Jan 26 '21 at 14:21

1 Answers1

3

OK after some trial and error I understand (more or less) what's happening. In the code above the array isn't fully allocated unless it's elements are 'touched'. By that I mean that the memory consumed isn't what I would expect it to be unless I do something like Array.Fill<byte>(b, 0) before storing the array in the static list. While I didn't know of this behavior it seems like some delayed allocation on the part of dotnet which does make sense in order to keep memory use down (ie don't actually allocate until you are going to use the array). If I use the Array.Fill then the memory climes much quicker and eventually does get paged out to swap.

So why did I get an OOM before? I believe the answer was that I was hitting the 2GB object size for the static list. This was a limit that I wasn't aware of but in dotnet no single object can go over 2GB. With the code above I believe enough memory was used up in the list object (the inner array, pointers to all the elements etc) that it hit that 2GB limit and cause the OOM.

Thanks everyone who read this and provided feedback.

shortspider
  • 1,045
  • 15
  • 34