limiting jail memory use with rctl/racct

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Wed, 24 Sep 2025 11:08:11 UTC
I wonder if people here use rctl to limit memory utilization for some practical 
purposes and what your experience is.

Recently I had a "bright" idea to limit memory use of Firefox (which, for me, 
tends to consume all memory and swap impacting everything else on the system).
Since Firefox is multi-process now, I decided to use a "null" jail as a resource 
container.
That is, a jail configured with path=/ mount.nodevfs host=inherit ip4=inherit.
There is no filesystem or network isolation (so, no security benefits), just 
grouping of related Firefox processes.

The memory limit is set with this rule:
jail:firefox-cage:memoryuse:deny=8g

I didn't know in advance how the memory limiting would affect Firefox and how 
Firefox would react to it, so I decided to go ahead and experiment.

I want to add that initially I also had a rule to limit swapuse but with it 
enabled, Firefox wouldn't even start.  When I removed the rule I observed that 
initially rctl reported some absurdly high and unstable swapuse for the jail. 
Gradually, it went down to some reasonable values.  Maybe there is some bug in 
RACCT code about accounting swap.

For example:
$ rctl -h -u jail:firefox-cage: | sort
coredumpsize=0
cputime=524
datasize=276K
maxproc=23
memorylocked=0
memoryuse=8236M
msgqqueued=0
msgqsize=0
nmsgq=0
nsem=0
nsemop=0
nshm=0
nthr=559
openfiles=5376
pcpu=93
pseudoterminals=0
readbps=0
readiops=0
shmsize=0
stacksize=8792K
swapuse=32G
vmemoryuse=73G
wallclock=3445
writebps=288
writeiops=2

One minute later:
$ rctl -h -u jail:firefox-cage: | sort
coredumpsize=0
cputime=588
datasize=312K
maxproc=26
memorylocked=0
memoryuse=8249M
msgqqueued=0
msgqsize=0
nmsgq=0
nsem=0
nsemop=0
nshm=0
nthr=633
openfiles=5496
pcpu=80
pseudoterminals=0
readbps=0
readiops=0
shmsize=0
stacksize=10M
swapuse=19G
vmemoryuse=73G
wallclock=5140
writebps=32K
writeiops=16

So, I had to ditch that rule although I find limiting memoryuse without limiting 
swapuse to be incomplete.

Also, I didn't even consider limiting vmemoryuse because it is very large, it is 
hard to predict and it seems to have little correlation with the physical memory 
use.

Regarding the experiment, Firefox more or less works, but not without issues.
When there are a lot of sites are open in tabs, especially some "web 
applications" that I have to use and which I know to be memory hogs, Firefox 
start glitching here and there.  Mostly it looks like some broken JavaScript.

Another observation is that memoryuse always stays somewhat above the 8 GB 
limit.  Sometimes it's just very slightly above, sometimes it's a couple of 
hundred megs (or a few percent) above, e.g., memoryuse=8455M.

And almost all the time I see a vmdaemon thread being active:
   PID USERNAME    PRI NICE   SIZE    RES STATE    C   TIME    WCPU COMMAND
    16 root        119    -     0B    16K CPU4     4  57.1H  68.98% vmdaemon

And it's always somewhere in this call chain:
procstat -kk 16
   PID    TID COMM                TDNAME              KSTACK
    16 100177 vmdaemon            - 
vm_swapout_object_deactivate+0x130 vm_swapout_map_deactivate_pages+0x1f3 
vm_daemon+0x87d fork_exit+0xc7 fork_trampoline+0xe

My impression is that vm_daemon is trying to inactivate some pages belonging to 
processes in the jail, so that they could get swapped out.  But either they get 
reactivated or the pageout code does not see a need to swap them out and they 
remain resident.

I'd say that this is kind of unexpected consequence.
It keeps a CPU core busy and doesn't allow the system to enter power saving states.

To conclude, this has a been useful experiment for me.
Initially, I had some naive expectations that memory limiting would just 
magically "limit memory".  The experiment forced me to think about what it 
actually means to limit memory, how it could be done, what consequences it would 
have and in what cases it could be useful.

If anyone has better suggestions and better experience, please let me know.

Thanks!
-- 
Andriy Gapon