I am trying to write a bash shell script that consumes a high amount of RAM on an embedded device for a user defined time. How do I do it without using arrays ?
-
im not versed in bash-fu but... whats wrong with using arrays? – Scott M. Feb 11 '11 at 01:43
-
Arrays are not supported on this limited shell on the embedded device. – Ankur Agarwal Feb 11 '11 at 01:49
-
8Then it's not Bash. – Dennis Williamson Feb 11 '11 at 01:51
-
Unless he means associated arrays, which are 'recent' in bash. In any case, I don't see how not using arrays is relevant for this problem. – raphink Feb 11 '11 at 15:13
-
If you have basic GNU tools, you can do `yes | tr \\n x | head -c $BYTES | grep n` because grep loads the input line-by-line in RAM. Because the line will be $BYTES long, it will load $BYTES in memory. Grep itself uses like 200KB, you might need to subtract that. If you also have bash, you can add the time: `cat <(yes | tr \\n x | head -c $((1024*1024*2))) <(sleep 4) | grep n` (for 2MB RAM because 1024*1024*2=2MB). If you have `pv` and want to slowly increase RAM use: `yes | tr \\n x | head -c $BYTES | pv -L $BYTESPERSEC | grep n` – Luc Jan 12 '16 at 22:56
-
@Luc: Your solution didn't work for me because `grep` crashes when given lines that are "too long"- perhaps a configuration issue. The following worked for me: `{ yes | head -c "$bytes"; sleep "$seconds"; } | tail -c "$bytes" >/dev/null`. – Matei David Feb 08 '16 at 21:29
-
4I might spell this `dd bs=250M if=/dev/zero of=/dev/null` to occupy 250MB – user128536 Apr 22 '16 at 22:44
-
To occupy 1GB (10^9 Bytes) for 10 seconds use `printf -v x %1000000000s; sleep 10; unset x`. This assumes a locale where each letter occupies 1 Byte (e.g. utf-8, c, iso-8859-1, ...). – Socowi Oct 01 '21 at 22:28
6 Answers
Even if traditional Bash arrays are not supported, it may still be possible to create array-like variables using the eval
command built into the particular shell.
The following example script is based on some scripting I did when using BusyBox in an embedded Linux project. BusyBox uses the Almquist shell (also known as A Shell, ash, and sh), which does not support arrays.
#!/bin/ash
for index in 1 2 3 4 5; do
value=$(($index * 1024))
eval array$index=\"array[$index]: $value\"
done
for i in 1 3 5; do
eval echo \$array$i
done
Be careful with quoting when using eval
!
Output:
array[1]: 1024
array[3]: 3072
array[5]: 5120
Depending on your particular scenario, a script similar to the following may suffice.
#!/bin/ash
echo "Provide sleep time in the form of NUMBER[SUFFIX]"
echo " SUFFIX may be 's' for seconds (default), 'm' for minutes,"
echo " 'h' for hours, or 'd' for days."
read -p "> " delay
echo "begin allocating memory..."
for index in $(seq 1000); do
value=$(seq -w -s '' $index $(($index + 100000)))
eval array$index=$value
done
echo "...end allocating memory"
echo "sleeping for $delay"
sleep $delay
In my brief testing, this script consumed ~570M to ~575M physical memory* for the specified time period of 5 minutes.
* Monitored using top and memprof programs in separate tests

- 15,458
- 6
- 54
- 72
Personally I would go with Nick's answer, since doing it in C is going to be much easier really.
But... if you really want to avoid writing a super-simple C program to do it, then (if the system is running Linux with the right stuff built in) you should be able to do it by mounting a tmpfs with a size limit of however much memory you want to use, then spewing data into a file in that tmpfs to fill it up (by, e.g., copying data from an infinite source (e.g., /dev/zero
).
The C program is really easier though, as long as you can compile for the platform.

- 6,428
- 1
- 30
- 39
If you have a /dev/shm
device, you can write to file located there, since it's a tmpfs by default.

- 3,625
- 1
- 28
- 39
@JohnBartholomew
Your idea about a tmpfs mount is also not that hard and you can be more sure that it's actually consuming RAM, right? (see Chris Dodd's comment at Nick's answer)
mount -t tmpfs none /new/path/for/temp -o size=32m
dd if=/dev/zero of=/new/path/for/temp/zero.txt bs=32m count=1
Probably dd
will complain that there is no space left on the device. Also, I don't know how much RAM will be used exactly, but if you're talking about MB's than this should be fine.

- 131
- 4
-
2The reason I'd go with the C option (though not malloc, specifically) is that you can then use the system memory management functions and be sure of exactly what effect you're having. e.g., mlock() can be used to make sure the kernel won't just push your allocation out to backing store. Note that tmpfs *is* backed by virtual memory, so really my suggestion suffers from the same problem as Nick's -- actually writing a file to fill the mount is just a hack to try to make sure the RAM is consumed. There may be some other ram-based file system you could use instead though I guess. – John Bartholomew Feb 11 '11 at 15:45
You need to distinguish between allocated and working-set RAM. It's easy to eat up memory in bash:
A="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
for power in $(seq 8); do
A="${A}${A}"
done
but unless the script churns through the data frequently then those pages of memory are good candidates to be swapped out.

- 5,375
- 1
- 21
- 27
I came up with this. /dev is a tmpfs
#!/bin/sh
mntroot rw
cd /dev
while :
do
dd > /dev/null 2>&1 if=/dev/zero of=myfile1 count=25000 bs=1024 # eat up 25 MB of RAM
usleep 1
rm myfile1
done

- 23,692
- 41
- 137
- 208