To start, read the attached picture to understand how the basics of memory allocation works in POSIX and Windows.
The cause of the problem is the transition from Reserved to Committed. On POSIX, it is implied. As a result, in Hermes code, there isn't a call that explicitly does that.
A shortcut was taken in my initial Windows port:
oscompat::vm_allocate on Windows returns memory that has been Committed.oscompat::vm_unused does nothing.For context, the point of vm_unused is to free the physical memory (but not virtual address space), and so that it doesn't count against our RSS. (Please correct me if this understanding is incorrect.)
The goal of this issue is:
vm_commit (MEM_COMMIT on Windows, no-op on posix)vm_allocate to reserve the memory without committing it (MEM_RESERVE on Windows, no change needed on posix)vm_unused with MEM_DECOMMIT on Windows. vm_* so that they invoke vm_commit before accessing the memory if vm_commit has not been invoked since the latest vm_allocate and vm_unused.
Tracked as T40416012 at Facebook.
As part of this task, once vm_unused is implemented, tests that exercised vm_unused can be re-enabled. However, those tests also exercises regionFootprint, which is a test-only function that isn't implemented for Windows. regionFootprint is certainly implementable on Windows.
I think it is very important to note that Hermes is committing incrementally on Windows, only it is happening with a granularity of a single segment (4MB).
To expand on what @tmikov commented.
With NCGen, Hermes reserves memories as 4MB segments. The expected outcome of this issue is not to break down the 4MB at commit time. In fact, I expect "commit" to still happen 4MB at a time. Instead, it is so that vm_unused can have meaningful impact (to reduce RSS) on Windows.
Thanks for the clarification. I haven't tested with NCGen yet.
vm_unused implementation would help for long running apps.
@mganandraj After a full GC we release unused 4MB segments to the OS, so you will get that behavior already, with 4 MB granularity.
I think this will actually be more relevant if PreAllocatedStorageProvider is used instead of VMAllocateStorageProvider.
PreAllocatedStorageProvider right now (on Windows) will reserve and commit the whole 500 MB range; however, it could be changed to only reserve the 500 MB range, and commit upon each call to newStorage.
PreAllocatedStorageProvider isn't the default yet for NCGen, but providing some experiments I'm working on go well, we might transition to using that on some platforms.
Most helpful comment
To expand on what @tmikov commented.
With NCGen, Hermes reserves memories as 4MB segments. The expected outcome of this issue is not to break down the 4MB at commit time. In fact, I expect "commit" to still happen 4MB at a time. Instead, it is so that
vm_unusedcan have meaningful impact (to reduce RSS) on Windows.