< Back to all hacks

#22 UV_THREADPOOL_SIZE=1

RAM
Problem
libuv spawns 4 worker threads by default, each consuming stack memory.
Solution
UV_THREADPOOL_SIZE=1 saves ~2 MB. No performance impact on single-core ARM32.
Lesson
Thread pools are sized for multi-core servers. Single-core devices waste RAM on idle threads.

Context

Node.js uses libuv for its event loop, and libuv maintains a thread pool for operations that can't be done asynchronously at the OS level: DNS lookups, file system operations, and some crypto functions. By default, this pool has 4 threads. Each thread allocates a stack (typically 512 KB on ARM32), plus associated kernel structures.

On the Moto E2's single-core Snapdragon 410, having 4 threads provides zero parallelism benefit. The CPU can only execute one thread at a time. The extra 3 threads just sit idle, consuming ~1.5 MB of stack allocations and adding context-switch overhead.

Implementation

Set the environment variable before starting Node.js:

# In your start script or .bashrc:
export UV_THREADPOOL_SIZE=1

For PocketClaw, this is set in the gateway start script ($PREFIX/bin/start-openclaw):

# In start-openclaw script:
export UV_THREADPOOL_SIZE=1
export NODE_OPTIONS='-r $HIJACK --expose-gc --no-warnings --max-old-space-size=112 --max-semi-space-size=2'
exec $PREFIX/bin/node22-icu $PREFIX/lib/node_modules/openclaw/dist/cli.js gateway run --port 9000

Verification

# Check the thread count of the Node.js process:
ps -T -p $(pgrep -f openclaw-gateway) | wc -l
# Expected: fewer threads than with UV_THREADPOOL_SIZE=4

# Verify the environment variable is set:
cat /proc/$(pgrep -f openclaw-gateway)/environ | tr '\0' '\n' | grep UV_THREADPOOL
# Expected: UV_THREADPOOL_SIZE=1

# Verify gateway still handles requests:
curl -s http://localhost:9000/api/status | head -1
# Expected: JSON response with status

Gotchas

  • Setting to 0 is invalid — libuv requires at least 1 thread
  • If your app does heavy parallel file I/O, reducing the pool could slow things down. PocketClaw is network-I/O bound so this is not an issue
  • The maximum value is 1024 (libuv hard limit)
  • This only affects the libuv thread pool, not V8 worker threads or other thread sources

Result

MetricBeforeAfter
libuv threads41
RAM saved0~2 MB
Performance impactbaselinenone measurable