
# Kenapa Jemalloc Bisa Turunkan Konsumsi RAM Node.js
Table of Contents
Pendahuluan
Pada aplikasi Node.js berumur panjang (API, worker, queue) sering terlihat RSS (Resident Set Size) terus naik walau heapUsed
relatif stabil. Salah satu pendekatan mitigasi adalah mengganti allocator default (glibc ptmalloc
atau musl
malloc) dengan jemalloc
.
Apa Itu jemalloc?
jemalloc
adalah general-purpose memory allocator fokus pada:
- Fragmentasi rendah
- Skalabilitas multi-thread (arena per thread)
- Background purging (kembalikan pages ke OS lebih cepat)
- Profiling heap terintegrasi
Masalah Umum Allocator Default
- Fragmentasi: blok kecil tercerai di page besar → RSS bengkak.
- Lock contention: banyak thread (misal libuv threadpool + native addon) rebutan global lock.
- Lambat merilis page ke OS (decay lambat).
Mekanisme Kunci jemalloc
- Arenas: beberapa arena mengurangi contention.
- Size classes (binning): alokasi seragam meminimalkan fragmentasi internal.
- Thread Cache (tcache): fast path free/alloc tanpa lock global.
- Background thread: purge dirty/muzzy pages.
- Decay tunable:
dirty_decay_ms
,muzzy_decay_ms
. - Heap profiling: sampling.
Kenapa Bisa Menurunkan RAM
- Fragmentasi eksternal lebih rendah → RSS mendekati heapNeeded.
- Page purging lebih agresif (dengan konfigurasi tepat).
- Overhead metadata efisien untuk pola alokasi kecil-menengah.
- Kontensi lebih kecil → latency GC & event loop tidak tersendat, mengurangi penumpukan objek sementara.
(Hasil selalu perlu dibuktikan—tidak semua workload diuntungkan.)
Kapan Tidak Terlalu Berguna
- Aplikasi sangat kecil / ephemeral (CLI cepat selesai).
- CPU-bound dengan sedikit alokasi memori.
- Container sangat ketat (overhead jemalloc bisa sedikit lebih besar di early phase).
- Sudah dioptimasi dan bottleneck bukan allocator.
Instalasi
Debian / Ubuntu
sudo apt updatesudo apt install -y libjemalloc2 libjemalloc-devldconfig -p | grep jemalloc
Biasanya path: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2
Alpine (musl)
apk add --no-cache jemalloc# Path umum:/usr/lib/libjemalloc.so.2
macOS (Homebrew)
brew install jemalloc# Path:/opt/homebrew/opt/jemalloc/lib/libjemalloc.2.dylib
Jalankan dengan:
DYLD_INSERT_LIBRARIES=/opt/homebrew/opt/jemalloc/lib/libjemalloc.2.dylib \node app.js
Docker (Debian slim)
FROM node:20-slimRUN apt-get update && apt-get install -y --no-install-recommends libjemalloc2 \ && rm -rf /var/lib/apt/lists/*ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2WORKDIR /appCOPY package*.json ./RUN npm ci --omit=devCOPY . .CMD ["node","server.js"]
Verifikasi Loaded
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 \node -e 'console.log(process.memoryUsage())' \| ldd /proc/$(pgrep -n node)/exe 2>/dev/null | grep jemalloc
Atau:
cat /proc/$(pgrep -n node)/maps | grep jemalloc
Integrasi ke Aplikasi Node.js
Script npm
Tambahkan di package.json
:
{ "scripts": { "start:jemalloc": "cross-env LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 MALLOC_CONF=background_thread:true,dirty_decay_ms:5000,muzzy_decay_ms:5000 node server.js" }}
Contoh MALLOC_CONF
background_thread:true
dirty_decay_ms:5000
muzzy_decay_ms:5000
prof:true,prof_leak:true,lg_prof_sample:17
(aktifkan saat profiling, bukan produksi permanen)
Contoh:
export MALLOC_CONF=background_thread:true,dirty_decay_ms:5000,muzzy_decay_ms:5000
Node Flags Pendukung
Kadang kombinasi dengan:
node --max-old-space-size=2048 server.js
Batas heap agar allocator tidak memicu overshoot RSS.
Monitoring & Profiling
Bandingkan Sebelum / Sesudah
Kode sederhana:
setInterval(() => { const m = process.memoryUsage(); console.log({ rss: (m.rss/1024/1024).toFixed(1)+'MB', heapUsed: (m.heapUsed/1024/1024).toFixed(1)+'MB', ext: (m.external/1024/1024).toFixed(1)+'MB' });}, 5000);
Amati apakah selisih rss - heapUsed
(fragmentation gap) mengecil.
Heap Profiling jemalloc
Aktifkan:
MALLOC_CONF=prof:true,prof_prefix:jeprof.out,lg_prof_sample:17 \LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 \node server.js
Gunakan jeprof
(bagian dari paket dev) untuk analisa.
Benchmark Sederhana (HTTP)
Install alat:
npm i -g autocannon
Jalankan dua sesi:
- Default malloc
- Dengan LD_PRELOAD jemalloc
Catat:
- p95 latency
- RSS setelah N detik
- Throughput (req/sec)
Jika jemalloc efektif, gap RSS turun dan p95 stabil atau lebih rendah.
Troubleshooting
- Crash awal: pastikan arsitektur cocok (x86_64 vs arm64).
- Tidak ada perubahan: workload tidak fragment-heavy; coba profiling GC (Chrome DevTools).
- RSS masih tinggi: periksa native addon atau buffer leak (misal tidak memanggil
.close()
). - Alpine: Node prebuilt kadang statically linked bagian tertentu; tetap tes.
Catatan Keamanan
Pastikan versi jemalloc terbaru (mitigasi CVE). Jangan aktifkan profiling di produksi permanen (overhead + file leak).
Ringkasan Langkah Cepat
- Install jemalloc (
apt install libjemalloc2
). - Set
LD_PRELOAD
ke path library. - (Opsional) Set
MALLOC_CONF=background_thread:true
. - Jalankan aplikasi & ukur gap RSS vs heapUsed.
- Simpan perbandingan sebelum vs sesudah.
Kesimpulan
jemalloc bukan jaminan, tetapi sering menurunkan RSS aplikasi Node.js yang padat alokasi dengan mengurangi fragmentasi dan mempercepat pelepasan halaman memori. Validasi selalu melalui metrik & benchmark nyata.