implement smart memory management
this is comprised of two parts: MemoryPressure and MemoryFence.
MemoryPressure
pressure is implemented using the sd-event API. in a thread we run an sd-event loop that issues pressure events. the pressure detection is entirely implemented inside sd-event. if memory pressure exceeds expectation an event is issued and we aggressively kill monitored sub-processes (i.e. gdb). the entire thing is implemented in a way that ideally does little to no memory allocation so it doesn't get stuck allocating memory we don't have.
(note that memorypressure can only work inside the monitored unit because of limitations in sd-event. therefor there is little point in putting gdb in its own unit - we'd need to have a secondary process inside the unit to implement monitoring which means greater complexity but would also make it less likely drkonqi as a whole gets OOM'd)
MemoryFence
fence is implemented using the systemd dbus API. by virtue of getting started by drkonqi-coredump-launcher drkonqi itself is part of a unit and can be memory constrained. that is the job of the fence. just before we start gdb in backtracegenerator.cpp we surround drkonqi with a memory fance. the fence essentially sets a MemoryHigh limit that is slightly lower than the available memory. the motivation here is that if there isn't enough memory we'll let gdb get killed (by the memorypressure) rather than cause the system to run out of memory.
(note that this is superior to simply putting gdb in a unit and setting a MemoryMax limit because this way we can tell when it was actually terminated because of a high pressure event)
Fence size
depending on the size of the fence we also alter gdb's behavior mode so it is less likely to actually hit the fence and get killed.
- spacious fence: this is the previous default where gdb does its default thing and loads all libs and their symbols on startup (possibly via debuginfod if the user has it enabled)
- some fence: instead of letting gdb load the symbols we load them in the preamble. advantage is that we only load the files we have frames for rather than all files
- little fence: in addition the solib loading only gets done on the crashing thread. this further limits the amount of affected files
- cramped fence: debuginfod is explicitly disabled and symbol files do not get loaded at all. this means that the trace is likely to be rubbish because it has no debug symbols and will need assistance from Sentry to become useful
the effective result is that gdb consumes decreasing amounts of memory, hopefully fitting inside the fence.
e.g. for crashinator a spacious fence has drkonqi peak at 11G while with a cramped fence it gets by with as little as 256M
UI
when a little or cramped fence is applied the user is additionally informed that closing applications may improve the trace quality by freeing memory
when gdb gets killed because of a high pressure event the user is informed about this