GICT knowledge base
How to Limit Process Resources with ulimit
Published
Every computer—no matter how powerful—has hardware limits. If you’ve ever watched your system slow to a crawl because a single process hogged all the CPU or memory, you know how important it is to keep runaway programs in check. On Linux and other UNIX-like operating systems, the ulimit command is your first line of defense. This unassuming shell built-in lets you set hard boundaries on how much CPU time, memory, file handles, and other resources a process can consume.
Whether you’re running a shared server, managing a development environment, or just want to avoid accidental system lockups, understanding how to use ulimit is a crucial skill. In this article, you’ll learn what ulimit does, how to use it to control resources, best practices, and how these limits can be managed both system-wide and per-user. You’ll see practical examples and learn to avoid common pitfalls, ensuring your system stays stable and reliable even when users or applications misbehave.
Prerequisites
Before you dive in, make sure you have:
- Access to a Linux or UNIX-like system (including macOS, BSD, etc.)
- A user account with shell access (root or sudo access is required for system-wide changes)
- Basic command-line knowledge
You don’t need to install anything—ulimit is built into most shells, including bash and zsh.
What Is ulimit?
ulimit is a shell command that lets you view or set user-level resource limits. These limits can prevent individual processes (or users) from using too much memory, opening too many files, or consuming too much CPU time.
Resource limits are enforced by the kernel and are inherited by any child processes. That means if you set a limit in your shell, every process you launch from that shell—including scripts, servers, editors, and background tasks—will be subject to those limits.
Resource limits fall into two categories:
- Soft limits: These can be changed by the process itself (up to the hard limit).
- Hard limits: These can only be lowered by the user, and only raised by the root user.
Common use cases for ulimit include:
- Preventing a runaway process from exhausting system memory.
- Limiting the number of files a user or application can open (helpful for web servers).
- Restricting CPU usage for background jobs.
- Keeping multi-user systems stable and fair.
How Does ulimit Work?
When you invoke ulimit, you’re actually interacting with your shell’s interface to the kernel’s resource limit system (setrlimit). Each shell (bash, zsh, etc.) provides the ulimit built-in, and its behavior is documented in that shell’s manual.
You can view the current limits by running:
ulimit -a
This prints a table of all current resource limits for your shell session. Sample output:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 256259
max locked memory (kbytes, -l) 65536
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 127061
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
Each line shows a specific resource, its unit, and the current limit. Some limits are “unlimited” by default, meaning there’s no enforced cap—unless you set one.
Common Resource Limits Managed by ulimit
Let’s break down some of the most important resources you can control with ulimit:
- CPU time (-t): Maximum number of CPU seconds a process can use.
- File size (-f): Largest file a process may create.
- Data segment size (-d): Maximum size of a process’s data segment (heap).
- Stack size (-s): Maximum stack size for a process.
- Core dump size (-c): Maximum size of core dump files created.
- Resident set size (-m): Maximum amount of physical memory a process can use.
- Number of open files (-n): Maximum file descriptors a process can open.
- Number of processes (-u): Maximum number of processes a user can create.
- Virtual memory size (-v): Maximum amount of virtual memory available to a process.
Understanding these options helps you set sensible, effective limits for your workflows or users.
Setting Limits with ulimit
You can set limits directly in your shell session or in shell scripts. For example, to limit the number of open files to 512:
ulimit -n 512
To set a limit for file size (in blocks, where 1 block = 512 bytes):
ulimit -f 10240
This restricts any process launched from your shell to creating individual files no larger than 5MB (10240 blocks x 512 bytes).
To restrict CPU time (in seconds):
ulimit -t 120
Any process using more than 2 minutes of CPU time will be terminated.
These changes apply only to your current shell session and its children. If you open a new terminal, the default limits apply again.
Soft vs. Hard Limits
To set a soft limit:
ulimit -Sn 512
To set a hard limit:
ulimit -Hn 1024
Soft limits can be increased by the user (up to the hard limit), while hard limits can only be increased by root.
Checking Current Limits
To check the current soft and hard limits for open files:
ulimit -Sn
ulimit -Hn
Setting Limits System-Wide
Shell limits are great for personal sessions, but what if you want to enforce limits system-wide or for specific users and services?
/etc/security/limits.conf
On most Linux systems using PAM (Pluggable Authentication Modules), you can set persistent, per-user or per-group limits in /etc/security/limits.conf.
Example entries:
# Limit all users to 4096 open files
* soft nofile 4096
* hard nofile 8192
# Limit user 'alice' to 100 processes
alice soft nproc 100
alice hard nproc 200
After editing this file, users must log out and back in for the new limits to take effect.
Systemd Service Limits
If you run services with systemd, you can configure resource limits in the service unit file.
Example:
[Service]
LimitNOFILE=4096
LimitNPROC=512
After changing these values, reload systemd and restart the service:
sudo systemctl daemon-reload
sudo systemctl restart yourservice
Bash Profile and Shell Scripts
You can add ulimit statements to your .bashrc, .bash_profile, or scripts to ensure limits are set every time your shell starts.
Example (~/.bashrc):
ulimit -n 2048
Practical Examples
Let’s look at a few real-world scenarios where ulimit can help you.
Example 1: Preventing a Memory Hog
Suppose you’re running a simulation or a script that sometimes gets stuck in an infinite loop, eating up all available memory. Set a memory limit before running the script:
ulimit -v 1048576 # Limit to 1GB virtual memory
./yourscript.sh
If the script tries to allocate more than 1GB, it will be killed, preserving your system’s responsiveness.
Example 2: Limiting Open Files for a Web Server
Web servers (like Nginx or Apache) can open thousands of file descriptors for serving content and handling connections. To avoid overwhelming the server, set a reasonable hard limit:
ulimit -Hn 4096
ulimit -Sn 2048
Add this to your server’s startup script or systemd unit file as needed.
Example 3: Restricting CPU Usage for Background Jobs
If you’re running CPU-intensive background jobs (compilation, video rendering, etc.), use:
ulimit -t 600
This gives each process a maximum of 10 minutes of CPU time. When the limit is reached, the process is terminated.
Example 4: Managing User Processes
On multi-user systems, a fork bomb can quickly bring down the system by spawning thousands of child processes. Prevent this by setting a hard nproc limit:
ulimit -Hu 256
ulimit -Su 128
This restricts how many concurrent processes a single user can create.
How Limits Are Enforced
When a process exceeds its allowed resources, the kernel steps in. Typically, the offending process receives a signal—often SIGXCPU (for CPU time), SIGXFSZ (for file size), or SIGKILL (for memory). The process may terminate immediately or have a chance to handle the signal and shut down gracefully. Either way, your system remains protected.
Checking Limits for Running Processes
If you need to check the limits for an already running process, inspect the /proc filesystem:
cat /proc/<pid>/limits
Replace <pid> with the process ID. Sample output:
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max open files 1024 4096 files
...
This table shows all limits applied to that process.
Best Practices for Using ulimit
- Start with Conservative Limits: Don’t set limits too low—test and adjust as needed for your workloads.
- Document Changes: If you change system-wide limits, keep a record and inform users or team members.
- Monitor Logs: Resource limit violations often show up in system logs (/var/log/syslog, /var/log/messages).
- Test in a Staging Environment: Always test new limits on non-production systems to avoid accidental service outages.
- Layer Your Defenses: Combine ulimit with cgroups, systemd limits, and container resource controls for comprehensive protection.
Troubleshooting Common Issues
Problem: Limits Aren’t Applying to Services
Check whether the service is managed by systemd, which often overrides shell-level limits. Confirm you’ve restarted the service and reloaded the systemd daemon after changing unit files.
Problem: Users Can Still Exceed Limits
Make sure limits are set in /etc/security/limits.conf and that PAM modules are enabled in /etc/pam.d/common-session or /etc/pam.d/login. Some desktop environments or SSH sessions may require additional configuration.
Problem: File Descriptors Still Run Out
Modern applications (like databases, web servers) may require much higher nofile limits than the defaults. Review software documentation for recommended settings and plan accordingly.
Alternatives and Related Tools
While ulimit is powerful, you may need more granular or advanced controls in some scenarios:
- Control Groups (cgroups): Used for limiting, accounting, and isolating resource usage of process groups. Essential for containers (Docker, LXC) and systemd.
- nice/renice: Adjust process priorities, not hard limits, but useful for tuning CPU scheduling.
- cpulimit: Caps CPU usage for a specific process, rather than all processes in a shell.
- resource: Python’s resource module allows scripts to set their own resource limits.
Combining these tools can give you even more control over your system’s resource allocation.
Security and Stability Considerations
Strict resource limits help prevent denial-of-service attacks, accidental misuse, and system crashes. For shared hosting, academic labs, or any multi-user environment, setting reasonable limits is a basic security hygiene measure. However, setting limits too low can break legitimate workloads, so always balance protection with usability.
Frequently Asked Questions
Will ulimit Slow Down My System?
No. ulimit simply sets thresholds—the kernel enforces these in the background, with negligible overhead.
Can I Remove Limits Once Set?
Soft limits can be raised (up to the hard limit) by the user. Hard limits can only be raised by root.
Is ulimit Permanent?
No. By default, ulimit changes in a shell or script only last as long as that session. For permanent changes, use /etc/security/limits.conf, systemd, or shell startup files.
What Happens If a Process Exceeds Its Limit?
The kernel sends a signal (usually terminating the process). Sometimes, you’ll see an error message or log entry.
Can I Set Limits for Docker or LXC Containers?
Yes. Containers use cgroups for resource control, which are even more flexible than ulimit. See the container runtime’s documentation for details.
Conclusion
Resource limits are a fundamental part of responsible system administration. By learning to use ulimit, you give yourself the power to protect your system from accidental or intentional resource abuse. Whether you’re running a personal laptop, managing a busy server, or administering a multi-user environment, setting smart limits keeps things fair and stable.
Remember: start with reasonable defaults, monitor your system, and adjust as needed. ulimit is just one tool in your Linux toolbox, but it’s one that can save you a lot of headaches down the road.
So next time you fire up that resource-hungry script or deploy a new service, take a moment to set some sensible limits. Your future self will thank you.
Related guides
How to Set Up zram on a Small VPS
Configure zram on Ubuntu with kernel and swap checks. Understand compressed memory limits, monitor real use and avoid unsafe swap-file changes.
LinuxHow to Find Services That Need a Restart After Updates with needrestart
Find services using outdated libraries with needrestart on Ubuntu. Read restart reports, review automatic restart policy and plan maintenance safely.
LinuxHow to Limit a Linux Service’s Memory with systemd
Limit a Linux service with systemd MemoryHigh, MemoryMax and swap controls. Check cgroup support, diagnose pressure and remove only your own policy.
LinuxHow to Protect SSH with CrowdSec on Ubuntu
Protect SSH with CrowdSec on Ubuntu. Connect log detection to firewall enforcement and test temporary blocking without losing administrator access.
