4 ms·
> See https://unix.stackexchange.com/a/521737 https://unix.stackexchange.com/a/521737 for example. I'm not convinced that the fork()/exec() issue is the correc
by wizeman 4y ago
> See https://unix.stackexchange.com/a/521737 https://unix.stackexchange.com/a/521737 for example.
I'm not convinced that the fork()/exec() issue is the correct justification, at least not entirely. As an example, Solaris supports fork()/exec() yet it doesn't do overcommit (at least not by default, I think) and has no OOM killer. And Solaris has a long history of being a very robust OS.
Also, in most cases I don't see what is the problem with reserving more disk space for swap (disk space which would almost never be used anyway), especially if the system becomes more robust as a result of that.
I think I recall Linus justifying memory overcommit by observing that the vast majority of applications don't handle out-of-memory conditions gracefully, so it's better for the OS to kill a misbehaving process (that is allocating too much memory) and let the others continue working normally than have every single process in the system have to handle out-of-memory failures, which they don't usually handle gracefully. But I'm not sure if I'm recalling this correctly.
I don't think either the overcommit design or the naive "all allocated address space must be reserved" design is the correct approach. I know almost nothing about Windows memory management, but it sounds to me like having "commit/uncommit memory" system calls separate from the "allocate/deallocate address space" system calls to be a better approach.
But I think the OS should try to reserve more space for the swap file before it starts returning ENOMEM to the "commit memory" system calls like Windows seems to be doing (judging from the blog post)...
- dblohm7 4y ago> But I think the OS should try to reserve more space for the swap file before it starts returning ENOMEM to the "commit memory" system calls like Windows seems to be doing (judging from the blog post)... One could just as easily argue similarly with respect to Unix and needing to loop over write watching for EINTR et al.
- wizeman 4y ago> One could just as easily argue similarly with respect to Unix and needing to loop over write watching for EINTR et al. I'm sorry, but I fail to see how that is related. EINTR is useful so that you can handle a signal in case it is received in the middle of a very long system call. For example, if an application is doing a write() on an NFS filesystem and the NFS server is not reachable (due to some network outage), the write() syscall could take minutes or hours before it completes. So it's good, for example, than you can Ctrl-C the process or send it a SIGTERM signal and abort the syscall in the middle of it, letting the application handle the signal gracefully. What I'm talking about is not related because allocating disk space on local disk (where the swap file would be located) is generally a very quick process. Mind you, only the disk space allocation is needed for reserving swap space -- it's not necessary to write anything to the swap file. In fact, it's not even necessary to actually allocate disk space, but I digress. And even if reserving swap space would take a long time, allowing the syscall to fail with EINTR would also work fine. What is not fine is letting the application believe that the system has completely run out of memory when in fact a lot of disk space can still be used for swap reservation.
- trelane 4y ago> I don't think either the overcommit design or the naive "all allocated address space must be reserved" design is the correct approach. Fortunately, this is tunable. You can also turn off overcommit entirely. https://www.kernel.org/doc/Documentation/vm/overcommit-accounting https://www.kernel.org/doc/Documentation/vm/overcommit-accou...
- wizeman 4y ago> Fortunately, this is tunable. You can also turn off overcommit entirely. I know, but as soon as I tried doing that, my systems started to experience unavoidable failures (although I don't remember exactly why, but I certainly don't think it was simply due to lack of swap space). Again, I don't remember exactly, but I suspect I experienced these failures because there are applications that expect Linux to be doing overcommit, or at least, they couldn't work without overcommit unless Linux added new features. I could be wrong (I'm not exactly a Linux memory management expert), but I think the root issue is that Linux is handling committed memory badly, because when you disable overcommit, Linux tries to reserve swap space for the entire allocated address space of all processes. But actually, this is not needed -- it's way too pessimistic and is extremely likely to lead to unnecessary memory allocation failures. What is needed is a way for applications to communicate with the kernel about which parts of the address space they might actually use (or not use) at any point in time, which may be significantly less (by orders of magnitude) than the amount of address space that they have allocated. Then you wouldn't need to reserve swap space for all the address space that processes have allocated, you'd only need to reserve swap space for the amount that the processes have declared to be (possibly) using. This could have a performance cost, but there are ways to reduce it, for example, by allowing this information to be declared in mmap() as a flag (which avoids doing 2 separate system calls in the typical case), by batching several syscalls into just one (similar to readv()/writev()), by using io_uring(), etc. I also think that, even if you want to use memory overcommit, then enabling overcommit should be done with (at least) process granularity, not for the whole system at once, which again, greatly limits the usefulness of disabling overcommit.
- trelane 4y agoYou may find mmap and mlock may be helpful.