You raise a limit with `ulimit` in your shell, but an already-running daemon still hits the old value. Explain how Linux resource limits (rlimits) are scoped, and the difference between a soft and a hard limit.
answer
- a per-process attribute, not a system setting
- inherited on fork, kept across exec
- your shell, its future children only
- soft is enforced, hard is the ceiling
- lowering a hard limit is one-way
basics
~20 sRlimits are per-process attributes, inherited across fork and kept across exec. A shell's ulimit changes only that shell and children it starts afterwards, never a running daemon. The soft limit is what is enforced; the hard limit is the ceiling the soft one may be raised to.
solid answer
~50 s`ulimit` is a shell builtin that calls `setrlimit` on the *shell process*. Because rlimits are per-process attributes inherited across `fork` and preserved across `exec`, the new value reaches only processes that shell starts from then on — a daemon started earlier, by a service manager, keeps whatever it inherited at launch. Each limit is a pair: the **soft** limit is the value actually enforced, and the **hard** limit is the ceiling. Any process may lower either, and may raise its soft limit up to the hard limit; raising the hard limit requires privilege — `CAP_SYS_RESOURCE`. Lowering a hard limit is irreversible for that process. You can read a running process's effective values from `/proc/<pid>/limits`, and change them from outside with `prlimit`, which wraps the `prlimit` system call. For a service, though, the durable fix is to set the limit where the service is launched, so it survives a restart.
code
bash · 3 linesulimit -Sn; ulimit -Hn # soft and hard open-file limits of this shell
cat /proc/1/limits # what PID 1 actually runs under
prlimit --pid 1234 --nofile=8192:8192go deeper
Know that ulimit sets limits on your shell and the processes it starts afterwards, and that each limit has a soft value that is enforced and a hard value that caps it.
Explain the inheritance model — limits copy on fork and survive exec — and the privilege rules: soft may move up to hard, lowering hard is one-way, raising hard needs privilege.
Be ready to diagnose from the failing process rather than your session: read its effective limits, adjust a running process from outside to confirm a theory, and then fix the limit where the service is actually launched.
Own the boundary between per-process rlimits and aggregate control-group limits in your platform's standards, so descriptor and core-dump policy sits in one place and memory containment sits in the other.
## What an rlimit is A resource limit is a per-process kernel attribute, one pair of numbers per resource, set with `setrlimit` and read with `getrlimit`. The kernel enforces them at the point of use: a limit on open files causes `open` to fail with `EMFILE`, a limit on address space causes `mmap` or `brk` to fail with `ENOMEM`, a limit on core size truncates or suppresses a core dump. They are not accounted globally — each process carries its own. The memory-related ones an interviewer might name: - **`RLIMIT_AS`** (`ulimit -v`) — total address space. Note that this caps *virtual* size, so it counts reservations that may never be backed by physical pages, which makes it a blunt and often surprising proxy for memory use. - **`RLIMIT_DATA`** — the data segment; on modern kernels it also covers anonymous mappings, so it constrains heap growth more directly than `RLIMIT_AS`. - **`RLIMIT_STACK`** (`ulimit -s`) — the main thread's stack growth. - **`RLIMIT_CORE`** (`ulimit -c`) — maximum core-dump size; zero disables dumps. - **`RLIMIT_NOFILE`** (`ulimit -n`) — open file descriptors, the limit most often hit in production. - **`RLIMIT_RSS`** (`ulimit -m`) exists but has had no effect on Linux since the early 2.4 series. Anyone proposing it to cap real memory use is remembering a system that has not behaved that way in twenty years — resident memory is bounded by control-group limits, not rlimits. ## Soft, hard, and who may change what Every resource has two values: - The **soft limit** is the one the kernel enforces. - The **hard limit** is the maximum the soft limit may be set to. An unprivileged process may set its soft limit anywhere from 0 up to its hard limit, and may lower its hard limit — but never raise it. That last part is what makes the hard limit a genuine sandbox boundary: a privileged launcher can drop the hard limit before executing untrusted code, and the code cannot climb back out. Raising a hard limit requires `CAP_SYS_RESOURCE`. ## Inheritance is the whole answer to the puzzle Rlimits are copied to the child on `fork` and survive `exec` unchanged — they are a property of the process, not of the program image. That gives the model its shape: the values a process runs under were fixed by whoever started it, and cannot be changed later from an unrelated shell. Your interactive shell's `ulimit` affects that shell and its future children only. Anything launched at boot by the service manager, or started earlier from a different session, is unaffected. ```bash # inspect a running process's effective limits cat /proc/1234/limits # change them from outside (soft:hard), needs privilege to raise the hard value prlimit --pid 1234 --nofile=8192:8192 ``` `prlimit` (util-linux) wraps the `prlimit` system call, which can read and modify the limits of another process — the escape hatch from the inheritance model, and useful for confirming a diagnosis. It is not a fix, because the change dies with the process; the durable place to set a limit is wherever the service is launched, so it applies again on restart. ## Rlimits versus control-group limits The distinction worth making explicit: an rlimit is a **per-process** cap enforced at the system-call boundary, returning an error the program can handle. A control group limit is a cap on an **aggregate of processes**, enforced by the memory subsystem, and exceeding it does not produce a return value the program sees. That is why rlimits remain the right tool for descriptor counts, core dumps and stack sizes, and the wrong tool for bounding a service's real memory footprint. ## Debugging pattern When a service fails with `EMFILE` or an unexplained allocation failure, do not check your shell — read `/proc/<pid>/limits` for the process that actually failed. The mismatch between what you set interactively and what the daemon inherited is one of the most common false leads in Linux troubleshooting, and being able to explain it cleanly is the point of the question.
- Why can an unprivileged process lower its hard limit but never raise it?Because the hard limit is a one-way boundary, which is what makes it useful for sandboxing. A privileged launcher can drop the hard limits before executing less-trusted code, knowing the code cannot climb back out; raising a hard limit requires `CAP_SYS_RESOURCE`. If a process could raise its own hard limit, the pair would collapse into a single advisory number with no security value.
- Why is `ulimit -m` not a way to cap a process's memory use on Linux?`RLIMIT_RSS`, which `ulimit -m` sets, has had no effect on Linux since the early 2.4 kernels — the kernel simply does not enforce resident-set limits through rlimits. To bound real memory use you put the process in a memory-limited control group, which caps the aggregate and acts through the memory subsystem. `RLIMIT_AS` is the nearest rlimit, but it limits address space, including reservations that were never going to consume RAM.
- How do rlimits differ from a control-group memory limit in how failure appears?An rlimit is enforced at the system call: the call returns an error such as `ENOMEM` or `EMFILE`, which the program can detect and handle. A control-group limit applies to a set of processes and is enforced by the memory subsystem — exceeding it triggers reclaim and, ultimately, a kill within that group, with no return value the program can inspect. One yields handled errors, the other yields a dead process.
saying these in an interview costs you the question
- Thinks ulimit changes apply to already-running processes
- Calls rlimits a system-wide setting
- Believes any process can raise its own hard limit
- Uses ulimit -m to bound resident memory on Linux
- Confuses per-process rlimits with cgroup limits