Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

How to Limit Process Resources with ulimit

Published

LinuxLinux and Commands

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

Account services are unavailable until the production backend is configured.