CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Performance Tuning / ulimit

ulimit

Show and set per-process resource limits

Intermediatelimitsprocessestuning

ulimit shows and changes the resource limits of your shell and everything it starts: open files, processes, core file size, stack size and more. 'Too many open files' errors, missing core dumps and fork failures usually come down to one of these limits.

Syntaxulimit [-S|-H] [-a | -n | -u | -c | -s | -v | -l ...] [LIMIT]

Watch it run

You want to see the limits your shell, and anything you start from it, are running with.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 2
ulimit -a

These are the soft limits. The two that bite most often: open files 1024 (a busy server needs thousands of sockets) and core file size 0 (crashes leave no core dump).

Anatomy of a command

$
commandulimit

A shell builtin (not a program): it changes the limits of the current shell process itself.

How it works

Every process has a set of resource limits (rlimits) stored in the kernel, each with a soft and a hard value. The kernel enforces the soft one: an open() beyond RLIMIT_NOFILE fails with EMFILE, a fork() beyond RLIMIT_NPROC fails with EAGAIN, a core dump is cut at RLIMIT_CORE. Any process can lower its limits or raise the soft value up to the hard value; raising the hard value needs root (CAP_SYS_RESOURCE). ulimit is built into the shell because it must call setrlimit() on the shell's own process; children inherit the limits through fork and exec. That is why the starting point matters: on login, PAM's pam_limits module applies /etc/security/limits.conf to SSH and console sessions, but services started by systemd never go through PAM. They get LimitNOFILE= and friends from their unit file, or systemd's defaults (DefaultLimitNOFILE=1024:524288). The real limits of any running process are in /proc/PID/limits, and prlimit can change them without a restart.

Login sessions get limits from PAM's limits.conf; systemd services get them from their unit. Children inherit, and the kernel enforces.

sessionnofile 65535fork + execread unitsetrlimitopen()open() #1025sshd loginssh app@hostpam_limitslimits.confapp - nofile 65535bashnofile 65535./workerinherits 65535systemdPID 1api.serviceno LimitNOFILEapi-servernofile 1024Kernelchecks open()
1/7
Login: PAM applies limits.conf

When you SSH in, sshd runs the PAM session stack. pam_limits reads /etc/security/limits.conf and limits.d and calls setrlimit before your shell starts.

← → to step

Options you'll actually use

-aShow all limits with their units
-nOpen file descriptors (files, sockets, pipes)
-uProcesses/threads per user (fork bomb protection)
-cCore file size in blocks (0 = no core dumps)
-sStack size in KB (default 8192)
-v / -mVirtual memory / resident set size (RSS limit isn't enforced on Linux)
-lLocked memory (mlock), matters for databases and eBPF
-S / -HSoft (enforced) / hard (ceiling); default sets both
/proc/PID/limitsThe limits a running process really has
LimitNOFILE=systemd unit setting; limits.conf does not apply to services

Common mistakes

Adding nofile to /etc/security/limits.conf for a systemd service

limits.conf is applied by PAM at login; systemd services don't log in, so it has no effect on them.

LimitNOFILE=65535 in the unit (systemctl edit SERVICE), then restart
Running ulimit -n 65535 in one terminal and restarting the service from another

ulimit changes only the current shell and its future children; services and other sessions are untouched.

Set the limit where the process is started (unit file, Docker --ulimit, Kubernetes node config)
ulimit -c 0 (or -n 1024) to change a limit 'temporarily'

Without -S, bash lowers the hard limit too, and a normal user can never raise it back in that session.

ulimit -S -c 0
Checking your own shell's ulimit -n to debug a service's EMFILE

Your shell's limits say nothing about another process's.

cat /proc/$(pgrep -f NAME)/limits, or prlimit --pid PID

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Print your soft and hard limits for open files.

  2. 2

    Raise the soft open-files limit to 4096 in a subshell only, and prove the parent shell is unchanged.

  3. 3

    Find the open-files limit of the running sshd process (or any root daemon).

Related commands

sysctlRead and tune kernel parameters at runtimelsofList open files, sockets and the processes holding themcoredumpctlFind and open core dumps captured by systemdsystemctlStart, stop, enable and inspect systemd services
PrevioussysctlNextnumactl
Linux / Performance Tuning / ulimit

ulimit

Show and set per-process resource limits

Intermediatelimitsprocessestuning

ulimit shows and changes the resource limits of your shell and everything it starts: open files, processes, core file size, stack size and more. 'Too many open files' errors, missing core dumps and fork failures usually come down to one of these limits.

Syntaxulimit [-S|-H] [-a | -n | -u | -c | -s | -v | -l ...] [LIMIT]

Watch it run

You want to see the limits your shell, and anything you start from it, are running with.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 2
ulimit -a

These are the soft limits. The two that bite most often: open files 1024 (a busy server needs thousands of sockets) and core file size 0 (crashes leave no core dump).

Anatomy of a command

$
commandulimit

A shell builtin (not a program): it changes the limits of the current shell process itself.

How it works

Every process has a set of resource limits (rlimits) stored in the kernel, each with a soft and a hard value. The kernel enforces the soft one: an open() beyond RLIMIT_NOFILE fails with EMFILE, a fork() beyond RLIMIT_NPROC fails with EAGAIN, a core dump is cut at RLIMIT_CORE. Any process can lower its limits or raise the soft value up to the hard value; raising the hard value needs root (CAP_SYS_RESOURCE). ulimit is built into the shell because it must call setrlimit() on the shell's own process; children inherit the limits through fork and exec. That is why the starting point matters: on login, PAM's pam_limits module applies /etc/security/limits.conf to SSH and console sessions, but services started by systemd never go through PAM. They get LimitNOFILE= and friends from their unit file, or systemd's defaults (DefaultLimitNOFILE=1024:524288). The real limits of any running process are in /proc/PID/limits, and prlimit can change them without a restart.

Login sessions get limits from PAM's limits.conf; systemd services get them from their unit. Children inherit, and the kernel enforces.

sessionnofile 65535fork + execread unitsetrlimitopen()open() #1025sshd loginssh app@hostpam_limitslimits.confapp - nofile 65535bashnofile 65535./workerinherits 65535systemdPID 1api.serviceno LimitNOFILEapi-servernofile 1024Kernelchecks open()
1/7
Login: PAM applies limits.conf

When you SSH in, sshd runs the PAM session stack. pam_limits reads /etc/security/limits.conf and limits.d and calls setrlimit before your shell starts.

← → to step

Options you'll actually use

-aShow all limits with their units
-nOpen file descriptors (files, sockets, pipes)
-uProcesses/threads per user (fork bomb protection)
-cCore file size in blocks (0 = no core dumps)
-sStack size in KB (default 8192)
-v / -mVirtual memory / resident set size (RSS limit isn't enforced on Linux)
-lLocked memory (mlock), matters for databases and eBPF
-S / -HSoft (enforced) / hard (ceiling); default sets both
/proc/PID/limitsThe limits a running process really has
LimitNOFILE=systemd unit setting; limits.conf does not apply to services

Common mistakes

Adding nofile to /etc/security/limits.conf for a systemd service

limits.conf is applied by PAM at login; systemd services don't log in, so it has no effect on them.

LimitNOFILE=65535 in the unit (systemctl edit SERVICE), then restart
Running ulimit -n 65535 in one terminal and restarting the service from another

ulimit changes only the current shell and its future children; services and other sessions are untouched.

Set the limit where the process is started (unit file, Docker --ulimit, Kubernetes node config)
ulimit -c 0 (or -n 1024) to change a limit 'temporarily'

Without -S, bash lowers the hard limit too, and a normal user can never raise it back in that session.

ulimit -S -c 0
Checking your own shell's ulimit -n to debug a service's EMFILE

Your shell's limits say nothing about another process's.

cat /proc/$(pgrep -f NAME)/limits, or prlimit --pid PID

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Print your soft and hard limits for open files.

  2. 2

    Raise the soft open-files limit to 4096 in a subshell only, and prove the parent shell is unchanged.

  3. 3

    Find the open-files limit of the running sshd process (or any root daemon).

Related commands

sysctlRead and tune kernel parameters at runtimelsofList open files, sockets and the processes holding themcoredumpctlFind and open core dumps captured by systemdsystemctlStart, stop, enable and inspect systemd services
PrevioussysctlNextnumactl