Limit the memory and cpu available for a user in Linux
For process related limits, you can have a look in /etc/security/limits.conf
(read the comments in the file, use google or use man limits.conf
for more information). And as jpalecek points out, you may use ulimit -a
to see (and possibly modify) all such limits currently in effect.
You can use the command quota
to see if a disk quota is in effect.
Limit memory usage for a single Linux process
There's some problems with ulimit. Here's a useful read on the topic: Limiting time and memory consumption of a program in Linux, which lead to the timeout tool, which lets you cage a process (and its forks) by time or memory consumption.
The timeout tool requires Perl 5+ and the /proc
filesystem mounted. After that you copy the tool to e.g. /usr/local/bin
like so:
curl https://raw.githubusercontent.com/pshved/timeout/master/timeout | \
sudo tee /usr/local/bin/timeout && sudo chmod 755 /usr/local/bin/timeout
After that, you can 'cage' your process by memory consumption as in your question like so:
timeout -m 500 pdftoppm Sample.pdf
Alternatively you could use -t <seconds>
and -x <hertz>
to respectively limit the process by time or CPU constraints.
The way this tool works is by checking multiple times per second if the spawned process has not oversubscribed its set boundaries. This means there actually is a small window where a process could potentially be oversubscribing before timeout notices and kills the process.
A more correct approach would hence likely involve cgroups, but that is much more involved to set up, even if you'd use Docker or runC, which among things, offer a more user-friendly abstraction around cgroups.
How to limit program runtime, memory usage and as a specific user programmatically in Linux
You'll want to use the setrlimit
syscall to limit memory (Process::RLIMIT_AS
). To limit the runtime of the program, you can only control the total number of seconds a process gets CPU time (so that doesn't account for time spent sleeping or waiting on I/O). That's done with Process::CPU
.
Drop privileges with Process::Sys.setgid
followed by Process::Sys.setuid
after setting these rlimits, but before calling your target process with Process::exec
.
Example target program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ALLOC_SIZE_1 1024
#define ALLOC_SIZE_2 (1024 * 1024 * 5)
int
main(int argc, char *argv[])
{
char *buf;
fprintf(stderr, "[+] uid: %d, gid: %d\n", getuid(), getgid());
fprintf(stderr, "[+] trying to allocate %d bytes (should succeed)...\n", ALLOC_SIZE_1);
if (NULL == (buf = malloc(ALLOC_SIZE_1))) {
fprintf(stderr, "[!] failed!\n");
return -1;
}
fprintf(stderr, "[+] success.\n");
free(buf);
fprintf(stderr, "[+] trying to allocate %d bytes (should fail)...\n", ALLOC_SIZE_2);
if (NULL != (buf = malloc(ALLOC_SIZE_2))) {
fprintf(stderr, "[!] succeeded! (should have failed.)\n");
return -1;
}
fprintf(stderr, "[+] ok. now doing infinite loop (should get killed pretty soon)...\n");
for (;;);
return 0;
}
And accompanying Ruby script to invoke it (run this script as root with, e.g. sudo /tmp/foo.rb
):
#!/usr/bin/env ruby
TARGET_GID = 99
TARGET_UID = 99
Process::setrlimit(Process::RLIMIT_AS, 1024 * 1024 * 5)
Process::setrlimit(Process::RLIMIT_CPU, 3)
Process::Sys.setgid(TARGET_GID)
Process::Sys.setuid(TARGET_UID)
Process::exec('/tmp/test')
And finally, output of running on my machine:
$ sudo ./run.rb
[+] uid: 99, gid: 99
[+] trying to allocate 1024 bytes (should succeed)...
[+] success.
[+] trying to allocate 5242880 bytes (should fail)...
[+] ok. now doing infinite loop (should get killed pretty soon)...
$
Limit available memory to a program
cgroups is the feature or modern linux kernels which allow you to limit resources like memory for group of processes (or for single process with threads). More about cgroups: https://en.wikipedia.org/wiki/Cgroups https://man7.org/linux/man-pages/man7/cgroups.7.html
The cgroups feature should be already enabled in your ubuntu 18.04 kernels. There are some descriptions how to use cgroups to limit memory:
- for systemd managed service: https://www.paranoids.at/cgroup-ubuntu-18-04-howto/,
- for docker containers
docker run --memory=1G ….
- for custom process tree with
cgcreate
/cgset
/cgexec
commands: https://dev.to/vga/how-to-see-and-limit-memory-consumption-of-an-application-5bfl something like
# Create a group for memory named “limited_group_1”
cgcreate -g "memory:limited_group_1" -t USERNAME:GROUPNAME
# Specify memory limit to 1G for this group
cgset -r memory.limit_in_bytes=1G "limited_group_1"
# Launch the application in this group
cgexec -g "memory:limited_group_1" ./YOUR_APPLICATION
# If needed, we can remove the group
cgdelete "memory:limited_group_1"
https://unix.stackexchange.com/questions/44985/limit-memory-usage-for-a-single-linux-process/279175#279175 was also mentioned in https://dev.to/vga/how-to-see-and-limit-memory-consumption-of-an-application-5bfl
PS: Default memory allocators in older glibc versions (malloc
, new
) has awful behavior for freed regions: they are not returned back without periodic malloc_trim()
library calls. You should try to link your application with libjemalloc or libtcmalloc which will replace malloc implementation of glibc with some code better in memory returning.
Limiting process memory/CPU usage on linux
You might want to investigate cgroups as well as the older (obsolete) ulimit.
Setting limit to total physical memory available in Linux
I found the answer I was looking for. Basically, the parameter that sets the total available physical memory is "mem=MEMORY_LIMIT". And this is a kernel boot parameter. You need to add, say "mem=1G" for maximum of 1GB available physical memory to the kernel boot parameter. For more info on how to add kernel boot parameters look at https://wiki.ubuntu.com/Kernel/KernelBootParameters
Memory Limit and CPU Limit in Docker Container
UPDATE
This is the answer that works: https://stackoverflow.com/a/41827812/3209177
I have just found this answer:
Limit memory on a docker container doesn't work
I am going to try that and come back with my observation.
Related Topics
Fork: Retry: Resource Temporarily Unavailable
Can't Find Out Where Does a Node.Js App Running and Can't Kill It
Linux Shell to Restrict Sftp Users to Their Home Directories
View a Log File in Linux Dynamically
Linux/Bash, Using Ps -O to Get Process by Specific Name
Mongodb Data Directory /Data/Db Not Found
How to Request a File But Not Save It with Wget
How to Purge Disk I/O Caches on Linux
Cut or Awk Command to Print First Field of First Row
Delete Files with String Found in File - Linux Cli
Does Os X Have an Equivalent to /Dev/Shm
Is It Safe to Delete the Journal File of Mongodb
How to Capture Raw Hid Input on Linux
Backup a Running Docker Container
PDF Compare on Linux Command Line