Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle out of memory gracefully in shell scripts

Is there a way to gracefully handle out-of-memory conditions in a shell script?

$ cat test.sh
#!/bin/sh
i=asdf
while true; do
  i="$i $i"
done
$ bash test.sh
test.sh: xrealloc: cannot allocate 18446744072098939008 bytes

Many programming languages allow handling out-of-memory exceptions using simple try-catch constructs. Is it possible to gracefully handle out-of-memory conditions in shell scripts / Bash as well? How?

Would it be possible to either free temporary buffers and attempt to continue execution, or do some custom error handling (save state) and exit with error?

like image 933
jotik Avatar asked Jun 26 '19 10:06

jotik


People also ask

How do you exit a shell script gracefully?

To end a shell script and set its exit status, use the exit command. Give exit the exit status that your script should have. If it has no explicit status, it will exit with the status of the last command run.

How do you handle errors in bash script?

To activate this "exit-on-error" behavior in bash, you can use the set command as follows. Once called with -e option, the set command causes the bash shell to exit immediately if any subsequent command exits with a non-zero status (caused by an error condition). The +e option turns the shell back to the default mode.

What is the purpose of #!/ Bin /< shell at the beginning of a script?

Now to explicitly specify the type of shell used by the script, Shebang is used. So we can use shebang, that is, #!/bin/bash at the start or top of the script to instruct our system to use bash as a default shell.


2 Answers

Not that I'm aware of. Instead, when you hit a problem like this, the normal approach is to raise the limits via ulimit.

ulimit -m N # for the heap
ulimit -s N # for the stack

However, to programmatically detect it, you'd have to do functionality similar to what strace does and watch for ENOMEM.

like image 199
tk421 Avatar answered Nov 16 '22 01:11

tk421


There's nothing as elegant as a try/catch on out of memory exception for Bash.

But you do have options for monitoring your memory consumption yourself.

http://man7.org/linux/man-pages/man5/proc.5.html

The simplest thing is to monitor the Kernel's OOM (out of memory) score for your process like this:

cat /proc/$$/oom_score

See more on the origin of the OOM score here: https://serverfault.com/a/571326/177301

The OOM score is a roughly percent-times-ten number.

Using your example, that would work like this:

#!/bin/sh

i=asdf
while true; do
  i="$i $i"

  if [ $(cat /proc/$$/oom_score) -gt 200 ]
  then
    echo "Abort: OOM score over 200" 1>&2
    exit 1
  fi

done

I experimented with this a little. On my Ubuntu VM the kernel would kill the script right after the OOM score hit 241. Your mileage may vary.

like image 44
ddoxey Avatar answered Nov 16 '22 03:11

ddoxey