a neat trick i found for reusing physical memory
23 points by signal-11
23 points by signal-11
I'm wondering about use cases for lazily duplicating large non-zero-initialized memory areas (preferably some where this complexity is worth the performance gains).
For multi-threaded programs where performance is important, CoW pages should carefully be not read before being written, otherwise there will be expensive TLB shootdowns due to the change of the physical address. CoW can be nice for small things but unfortunately doesn't scale well.
That's what the Darwin shared cache is. All of the OS userspace is mapped as a single shared region in all processes, constant initialized regions are as well as CoW, etc
It has another benefit (or, at least, did. I presume it still does). The region is fairly large and contains a bunch of pages in different places. This means it will often miss in the TLB. It turns out TLB misses on modern systems are not that bad if the page tables are all in cache, especially if they’re all in L1. XNU maps all of the read-only (including execute) shared region using the same page-table pages. The root of the page table in every macOS / iOS app has one entry that points to the same page. The page table walkers keep those pages in L1 so accessing them is faster.
This alone, I’m told, gave a 1-10% performance improvement on app performance when they rolled it out.
It’s a really neat trick. It’s a shame F/OSS ecosystems are so fragmented that there isn’t a common set of libraries that everyone would want. And things like Flatpack are making this worse by making it easier to ship different versions of the same libraries.
this is cool because regardless of the size of the initial allocation, the copy isn't taking up any physical memory
The PTEs for the demand-mapped pages of the copy allocation take up physical memory at a rate of only 1/512 ~= 0.2% assuming all pages of the 2 MB range are mapped. But 0.2% is not 0%. And this overhead becomes 100% if there's only one mapped page in the 2 MB range. The same pattern repeats at the coarser scales of the page table, but the PTE level is usually what's worth thinking about if at all. The VmPTE metric for Linux processes counts the overhead at several levels.
(The concrete numbers assume x86-64 and small pages.)
it's a cool trick! and i wonder whether there's an equivalent for windows
Yes, but you have to use file-backed mappings. Windows has a temp-file attribute that you can set that gives you swap-like behaviour (writes to memory are not required to be written back to disk ever, though they may be).
Be a little careful on Windows though because this is the one place NT makes an exception to its ‘don’t make promises you can’t keep’ rule in the memory manager. Private (CoW) mappings of a file don’t count against your commit charge until you take the CoW fault. If there is no available commit, you get an exceptions (SEH or VEH).