zirias@
Developer
Background: working on some service written in C that's using a BTREE database as provided by dbopen(3). This seems to use caching in memory extensively, so if you don't want to force a
As there's no sane way to recover from OOM, I'm using the
This works perfectly fine when just simulating an allocation error. But trying to get a real one, I had to learn malloc(3) just won't fail, even when trying to allocate more than your physical RAM + swap. Instead, the OOM killer will wreak havoc randomly killing large processes when you attempt to use that memory that doesn't really exist. ?
So, I came across the
Therefore, I tried
(yes, there are two empty log lines from the kernel ...)
What's happening here? And is there a sane way to tell FreeBSD to fail on memory allocations that can obviously never be fullfilled?
sync()
after every change, you should make sure it's properly closed on exit if you don't want to lose data.As there's no sane way to recover from OOM, I'm using the
xmalloc()
paradigm: wrap malloc(3) in a function that just exists on error. Normally, you use abort(3) for that, but then, there's no cleanup code executed. You could attempt to clean up from some SIGABRT
signal handler, but that's fragile and cumbersome. So I came up with a different idea: My own "panic" function using longjmp(3) to throw away most of the calling stack, but still execute the final cleanup.This works perfectly fine when just simulating an allocation error. But trying to get a real one, I had to learn malloc(3) just won't fail, even when trying to allocate more than your physical RAM + swap. Instead, the OOM killer will wreak havoc randomly killing large processes when you attempt to use that memory that doesn't really exist. ?
So, I came across the
vm.overcommit
sysctl. tuning(7) has the following to say about it:
Code:
Setting bit 0 of the vm.overcommit sysctl causes the virtual memory
system to return failure to the process when allocation of memory causes
vm.swap_reserved to exceed vm.swap_total. Bit 1 of the sysctl enforces
RLIMIT_SWAP limit (see getrlimit(2)). Root is exempt from this limit.
Bit 2 allows to count most of the physical memory as allocatable, except
wired and free reserved pages (accounted by vm.stats.vm.v_free_target and
vm.stats.vm.v_wire_count sysctls, respectively).
Therefore, I tried
sysctl vm.overcommit=1
. A second later, my kernel (13.0-RELEASE-p4) panicked:
Code:
kernel:
syslogd: last message repeated 1 times
kernel: Fatal trap 12: page fault while in kernel mode
kernel: cpuid = 2; apic id = 02
kernel: fault virtual address = 0x18
kernel: fault code = supervisor write data, page not present
kernel: instruction pointer = 0x20:0xffffffff80ca2596
kernel: stack pointer = 0x28:0xfffffe00deaccb20
kernel: frame pointer = 0x28:0xfffffe00deaccb80
kernel: code segment = base 0x0, limit 0xfffff, type 0x1b
kernel: = DPL 0, pres 1, long 1, def32 0, gran 1
kernel: processor eflags = interrupt enabled, resume, IOPL = 0
kernel: current process = 2317 (chrome)
kernel: trap number = 12
kernel: panic: page fault
kernel: cpuid = 2
kernel: time = 1641225063
kernel: KDB: stack backtrace:
kernel: #0 0xffffffff80c58a85 at kdb_backtrace+0x65
kernel: #1 0xffffffff80c0b461 at vpanic+0x181
kernel: #2 0xffffffff80c0b2d3 at panic+0x43
kernel: #3 0xffffffff8108c1b7 at trap_fatal+0x387
kernel: #4 0xffffffff8108c20f at trap_pfault+0x4f
kernel: #5 0xffffffff8108b86d at trap+0x27d
kernel: #6 0xffffffff81062f18 at calltrap+0x8
kernel: #7 0xffffffff80ca138b at shm_truncate+0x5b
kernel: #8 0xffffffff80c77fa1 at kern_ftruncate+0xa1
kernel: #9 0xffffffff8108cabc at amd64_syscall+0x10c
What's happening here? And is there a sane way to tell FreeBSD to fail on memory allocations that can obviously never be fullfilled?