diff options
| author | Taylan Kammer <taylan.kammer@gmail.com> | 2026-08-21 21:24:32 +0200 |
|---|---|---|
| committer | Taylan Kammer <taylan.kammer@gmail.com> | 2026-08-21 21:24:32 +0200 |
| commit | e01902c93ee686f64364efe6ea6ebc79b5cbf1a5 (patch) | |
| tree | fbcef2e96a42eb02c721fdcaba1ddc860d39e7ae | |
| parent | 37b5d3093c40c24aaad3662db23f883910eb7bd3 (diff) | |
Add note.
| -rw-r--r-- | notes/260821-overcommit.md | 92 | ||||
| -rw-r--r-- | notes/index.md | 1 |
2 files changed, 93 insertions, 0 deletions
diff --git a/notes/260821-overcommit.md b/notes/260821-overcommit.md new file mode 100644 index 0000000..69c566a --- /dev/null +++ b/notes/260821-overcommit.md @@ -0,0 +1,92 @@ +# Virtual Memory Overcommit + +_2026 August_ + +There's a distinction between reserving virtual memory and having it +"committed" by the kernel. + +This isn't the same thing as it being backed by physical memory. One +could think of the state of vmem as having three levels: + +1. Reserved + +2. Committed + +3. Physically backed + +Also, the physical backing could be RAM or SWAP, but that's not +important for our case. What matters is that reserving is always +"free" because it's just a reservation within the virtual address +space of the process itself, whereas committing *may* be checked +against the available RAM/SWAP of the whole system, and possibly +denied even before it needs physical backing. There may also be +explicit commit limits unrelated to RAM/SWAP availability. + +Committing memory despite the system potentially not having enough +RAM/SWAP is called overcommit. + +## When is overcommit allowed + +According to some quick research (don't cite this) the breakdown of +which kernels allow overcommit is as follows: + +* MacOS: Always allowed. + +* Linux, FreeBSD, NetBSD: Allowed by default; configurable. + +* OpenBSD, MS Windows: Not allowed. + +So, for Zisp to cover even just all POSIX systems, it will need some +way to reserve without committing. + +## How to reserve without commit + +Under POSIX, you reserve without committing by calling `mmap()` with +`PROT_NONE` for the protection argument. Of course, the behavior is +not actually documented as part of POSIX, but I suppose it should be +safe to assume that any sane implementation would not count memory +that's inaccessible towards any kind of commit limit. Surprisingly, +even the Linux documentation doesn't *explicitly* guarantee that a +`PROT_NONE` mapping is "free" but I think it's safe to assume given +there's projects in the wild like jemalloc and the JVM that already +use this trick, so Linux wouldn't dare change the behavior. + +There's also `MAP_NORESERVE` under Linux, which can achieve the same +effect, but I guess it's less portable. Funnily, there's even some +old discussions about the kernel not honoring `MAP_NORESERVE` under +strict overcommit policies, while `PROT_NONE` works. Oh and also, +"NORESERVE" flies in the face of the terminology I use here, and +there's also comments on LWN about how it's a misnomer: + +[https://lwn.net/Articles/627557/](https://lwn.net/Articles/627557/) + +Anyhow, TL;DR: Use `PROT_NONE` on POSIX; it should hopefully work as +desired on any common POSIX system besides OpenBSD. + +On MS Windows, you reserve by calling `VirtualAlloc()` with the +`MEM_RESERVE` flag, and commit with the `MEM_COMMIT` flag. + +## Committing as you go + +When you've reserved without commit, you then actually need to tell +the kernel when you need the memory committed. + +On POSIX, you can't use it under `PROT_NONE` anyway (the whole point) +and asking the system to commit it is a matter of calling `mprotect()` +to set the protection mode to `PROT_READ | PROT_WRITE` instead. + +Likewise, on MS Windows, trying to access in any way a region of vmem +not yet committed is an error; you need to call `VirtualAlloc` again, +on a sub-range of the full range, with `MEM_COMMIT` this time. + +## Disadvantages + +Syscalls are costly! Would be great if we only ever needed a single +one at startup, but alas. + +Thankfully, after my latest tweaks to Meta Alloc, it already bumps +watermarks in chunks of at least 64 KiB. That's a perfect spot for +inserting the `mprotect()` or `VirtualAlloc()` calls. + +I may just do that unconditionally, at least for now, because it's +easy to make it configurable if ever needed. diff --git a/notes/index.md b/notes/index.md index 7bdde42..a46f2d5 100644 --- a/notes/index.md +++ b/notes/index.md @@ -37,3 +37,4 @@ * [Further list array optimization](260626-fastcons5.html) * [Allocation strategy](260727-alloc.html) * [Releasing virtual memory](260817-release.html) +* [Virtual memory overcommit](260821-overcommit.html) |
