Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -O2 -g
uname output: Linux 4.19.x x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu
Bash Version: 5.0 / 5.1 / 5.2 / 5.3 (vanilla upstream sources)
Patch Level: latest available for each release
Description:
In an interactive shell, executing a fork-heavy loop with command substitution
twice consecutively exhibits a ~2.5x slowdown on the second and subsequent runs:
time for i in {1..10000}; do echo $(date) >/dev/null; done # ~16s
time for i in {1..10000}; do echo $(date) >/dev/null; done # ~40s
time for i in {1..10000}; do echo $(date) >/dev/null; done # ~40s
The slowdown persists for the shell's lifetime, including subshells spawned
from it.
Bisecting build configurations and bash versions reveals the slowdown requires
both:
Bash 5.x series (5.0 onward; 4.4 unaffected)
./configure --with-bash-malloc=no (bash uses glibc malloc)
Either condition alone does not trigger the issue:
| Bash Version | Malloc | Run 1 | Run 2 | Status |
| 4.4.19 | bash builtin | 15.2 s | 15.4 s | normal |
| 4.4.19 | glibc | 15.1 s | 15.4 s | normal |
| 5.0/5.2/5.3 | bash builtin | 17.0 s | 17.1 s | normal |
| 5.0/5.2/5.3 | glibc | 16.6 s | 40.3 s | regression |
The regression with --with-bash-malloc=no persists across all 5.x releases,
including the current master HEAD:
| Bash Version (vanilla) | --with-bash-malloc=no Run 1 / Run 2 |
| 4.4.19 | 15.1 s / 15.4 s (normal) |
| 5.0 | 16.6 s / 40.3 s (regression) |
| 5.1 | ~17 s / ~40 s (regression) |
| 5.2 | ~17 s / ~40 s (regression) |
| 5.3.0 release tag | 16.4 s / 39.9 s (regression) |
| master HEAD (5.3.9, commit 637f5c8 with 5.3 patches 1-9) | 16.3 s / 40.0 s
(regression) |
展开
No released or development version of bash 5.x resolves this when built with
--with-bash-malloc=no.
Additional Observations:
Trigger Condition: Loop body must involve both fork and execve. Builtins or
fork-only operations (e.g., x=$(:)) do not trigger the issue.
Environment: Reproduces only in interactive shells (PTY-attached).
Non-interactive scripts are unaffected.
Debugging: Running under strace masks the slowdown.
Reproduction Steps:
Build vanilla bash 5.2 with --with-bash-malloc=no.
Execute in a real PTY interactive shell:
script -qc "/path/to/bash -i" /dev/null <<'EOF'
time for i in {1..10000}; do echo $(date) >/dev/null; done
time for i in {1..10000}; do echo $(date) >/dev/null; done
EOF
Rebuild with default --with-bash-malloc=yes to confirm the slowdown disappears.
Verified Workarounds:
Build with ./configure --with-bash-malloc=yes (default). Eliminates the
regression across all tested 5.x versions.
Use LD_PRELOAD=/usr/lib64/libjemalloc.so.2 on a --with-bash-malloc=no build.
Prevents the slowdown on subsequent runs.
Thanks
Roy