Linux Process Management for Developers
Understanding Linux process management is essential for debugging performance issues, troubleshooting stuck applications, and optimizing resource usage. Every running program on Linux is a process, and the kernel provides a rich set of tools to inspect, monitor, and control them. This article covers the essential commands and concepts every developer should know.
Inspecting Running Processes
The ps command provides a snapshot of currently running processes. With different options, you can customize the output to show the information most relevant to you. The combination ps aux shows all processes from all users in a detailed format including CPU and memory usage. For real-time monitoring, htop provides an interactive, color-coded interface with tree view, filtering, and the ability to send signals to processes directly. The --sort flag lets you order processes by memory or CPU usage to quickly identify resource hogs.
# List all processes with custom output format
ps -eo pid,ppid,cmd,%mem,%cpu,user --sort=-%mem | head -20
# Show process tree
ps auxf
# Real-time monitoring
htop
# F5: tree view | F4: filter by name | F9: kill process
# Find a specific process by name
pgrep -fl nginx
# Detailed information about a specific PID
ps -fp 1234
ls -l /proc/1234/
The /proc filesystem is a virtual filesystem that exposes kernel data structures as files. Each running process has a directory at /proc/PID/ containing information about its command line (cmdline), environment variables (environ), open file descriptors (fd/), memory mappings (maps), and status (status). Reading these files programmatically is often faster and more flexible than parsing command output.
Systemd Service Management
Modern Linux distributions use systemd as the init system. Services are defined by unit files (.service files in /etc/systemd/system/) and managed with the systemctl command. Systemd handles starting services at boot, restarting them on failure, and collecting their logs through journald. Always check the status of a service before debugging other issues — the status output shows whether the service is running, the last few log lines, and whether it is enabled to start at boot.
# Manage services
systemctl status nginx # check status and recent logs
systemctl start nginx # start a service
systemctl stop nginx # stop a service
systemctl restart nginx # restart (reload config)
systemctl enable --now docker # enable at boot and start now
# View logs for a service
journalctl -u nginx -f # follow logs in real time
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -p err # only error level and above
# Create a custom service unit
cat > /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My Python Application
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/main.py
Restart=on-failure
RestartSec=5
EnvironmentFile=/opt/myapp/.env
[Install]
WantedBy=multi-user.target
EOF
Control Groups (cgroups)
Cgroups allow you to limit and account for the resource usage of process groups. Systemd exposes cgroup v2 through service unit properties. You can set CPU quotas, memory limits, and I/O weights to prevent one service from starving others. This is the foundation of container resource limits in Docker and Kubernetes.
# Set resource limits on a systemd service systemctl set-property myapp.service CPUQuota=50% # max 50% of one CPU systemctl set-property myapp.service MemoryMax=512M # max 512 MB RAM systemctl set-property myapp.service IOWeight=100 # I/O priority # View cgroup limits and current usage systemctl show myapp.service | grep -E 'CPUQuota|MemoryMax|IOWeight' cat /sys/fs/cgroup/system.slice/myapp.service/memory.current cat /sys/fs/cgroup/system.slice/myapp.service/cpu.stat # Check OOM kills dmesg | grep -i "killed process"Signals and Killing Processes
Signals are the Linux mechanism for notifying processes of events. The most commonly used signals are SIGTERM (15) — a polite request to terminate, allowing graceful cleanup — and SIGKILL (9) — an immediate forced termination that the process cannot catch or ignore. Always try SIGTERM first and only use SIGKILL as a last resort. The
killcommand sends signals by PID, whilekillallandpkillsend signals by process name. TheSIGHUPsignal (1) is often used to tell daemons to reload their configuration without restarting. For background jobs,jobs,fg, andbglet you manage running and suspended processes interactively.# Send signals kill -15 1234 # SIGTERM — graceful shutdown kill -9 1234 # SIGKILL — force kill (last resort) killall -15 nginx # SIGTERM all nginx processes pkill -f "python.*server" # kill by command pattern # Reload configuration (SIGHUP) kill -1 1234 systemctl reload nginx # equivalent for systemd services # Manage background jobs sleep 100 & # start in background jobs # list background jobs fg %1 # bring job 1 to foreground Ctrl+Z # suspend foreground job bg %1 # resume suspended job in backgroundThe
nohupcommand runs a process that ignores SIGHUP (so it survives terminal closure) and redirects output tonohup.out. This is useful for long-running SSH sessions where you want a process to continue after disconnecting. For more robust background execution, usetmuxorscreenterminal multiplexers — they create persistent sessions that survive network interruptions and can be reattached later.Monitoring process health is an ongoing task. Use
htopfor interactive debugging,systemctlfor service management,journalctlfor log analysis, and cgroups for resource limits. Combining these tools gives you full visibility into what your system is running and how resources are being consumed.

