0

How come when I try to allocate a byte in every loop, the amount of virtual memory never got reduced as shown in the cout of statex.ullAvailVirtual???

If I change the dynamic memory allocation to VirtualAlloc(), in every loop I can see the size of virtual memory reduced by 4 bytes, which is logical since the size of a page is 4 bytes.

#include <Windows.h>
#include <iostream>

int main()
{
    unsigned int allocated = 0;

    while (true)
    {
        MEMORYSTATUSEX statex;

        statex.dwLength = sizeof(statex);

        GlobalMemoryStatusEx(&statex);

        //Depleting the memory per byte.
        char* dyn_mem = new char[1];
        *dyn_mem = 'a';


        std::cout << "There are " << statex.ullAvailVirtual / 1024 << " free  KB of virtual memory." << std::endl;
    }
    return 0;
}
caramel1995
  • 2,968
  • 10
  • 44
  • 57
  • Not sure on what machine you're running that the page size is 4 bytes. But the memory change (or absence thereof) can be caused by memory caching. I think this depends on how your compiler implements memory allocation (`malloc` and such). – Timo Apr 06 '20 at 12:03
  • Your compiler may simply remove this allocation. It does nothing. – freakish Apr 06 '20 at 12:07
  • I did experiment by putting the value of `*dyn_mem`, it's the same. By right compiler shouldn't removed it since I am using it in this context. – caramel1995 Apr 06 '20 at 12:09
  • If you disable optimization (default debug configuration in Visual Studio) it shouldn't be optimized away anyway. – Timo Apr 06 '20 at 12:10
  • @caramel1995 you are using it, but the compiler may easily prove that your function works exactly the same with or without the allocation (and related code). And so it will remove the unnecessary code. That's how optimizations work. Here's an example: https://godbolt.org/z/F2N3Vj – freakish Apr 06 '20 at 12:13

1 Answers1

1

What you're seeing is a memory allocation optimization. See this answer for more details on how allocation and deallocation work. Basically, it's very inefficient to allocate each byte at a time from the OS (or maybe impossible alltogether), because it usually handles memory in pages (on my system 4KB) and not single bytes.

The compiler vendors for your platform (Microsoft if you use msvc in this case) know this very well and implement the low level memory allocations in a way so that they handle sub-page allocations. malloc for example, may allocate one page of memory on application startup. The program may doesn't need that much memory at startup so malloc keeps track of what it requested from the OS and what the application requested from malloc. If malloc runs out of space it requests another page from the OS.

The standard library container (like std::vector) work in a very similar way (see std::vector::resize and std::vector::reserve).

If you ramp up your allocation to 10 bytes per iteration (instead of 1) you will see the memory changing rather quickly. In my case you can see the transition happen:

There are 137434705464 free  KB of virtual memory.
There are 137434705464 free  KB of virtual memory.
There are 137434705464 free  KB of virtual memory.
There are 137434701368 free  KB of virtual memory.
There are 137434701368 free  KB of virtual memory.
There are 137434701368 free  KB of virtual memory.

You can see there is one change of 4096 bytes which matches the page size on my system. At this point malloc (or whatever allocation function is used) ran out of reserved memory and requested a new chunk.

Note that I used malloc here as a placeholder for any common memory allocation function.

Timo
  • 9,269
  • 2
  • 28
  • 58
  • You mean windows pre-allocate page during the app startup, and when I try to allocate a byte of memory, it make use of the pre-allocate page??? – caramel1995 Apr 06 '20 at 12:53
  • @caramel1995 not windows, but the C++ runtime, yes. – Timo Apr 06 '20 at 12:54
  • ahh, got it. since `malloc` and `new` construct is C and C++ keywords, the implementation is up to the person who design the compiler. – caramel1995 Apr 06 '20 at 13:07
  • @caramel1995: it's likely that the implementation needed a few bytes for `std::cout` anyway, but not exactly a whole page. Also, `malloc` isn't actually a keyword, but a standard library function. You're allowed to use `malloc` as a name in other namespaces. Keywords are universally reserved. – MSalters Apr 06 '20 at 13:50