Jemalloc

# 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

  1. Fragmentasi eksternal lebih rendah → RSS mendekati heapNeeded.
  2. Page purging lebih agresif (dengan konfigurasi tepat).
  3. Overhead metadata efisien untuk pola alokasi kecil-menengah.
  4. 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

Terminal window
sudo apt update
sudo apt install -y libjemalloc2 libjemalloc-dev
ldconfig -p | grep jemalloc

Biasanya path: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2

Alpine (musl)

Terminal window
apk add --no-cache jemalloc
# Path umum:
/usr/lib/libjemalloc.so.2

macOS (Homebrew)

Terminal window
brew install jemalloc
# Path:
/opt/homebrew/opt/jemalloc/lib/libjemalloc.2.dylib

Jalankan dengan:

Terminal window
DYLD_INSERT_LIBRARIES=/opt/homebrew/opt/jemalloc/lib/libjemalloc.2.dylib \
node app.js

Docker (Debian slim)

Terminal window
FROM node:20-slim
RUN 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.2
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node","server.js"]

Verifikasi Loaded

Terminal window
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:

Terminal window
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:

Terminal window
export MALLOC_CONF=background_thread:true,dirty_decay_ms:5000,muzzy_decay_ms:5000

Node Flags Pendukung

Kadang kombinasi dengan:

Terminal window
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:

Terminal window
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:

Terminal window
npm i -g autocannon

Jalankan dua sesi:

  1. Default malloc
  2. 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

  1. Install jemalloc (apt install libjemalloc2).
  2. Set LD_PRELOAD ke path library.
  3. (Opsional) Set MALLOC_CONF=background_thread:true.
  4. Jalankan aplikasi & ukur gap RSS vs heapUsed.
  5. 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.

Dika Ardianta

Terima kasih telah membaca artikel di website ini. Jangan ragu untuk menjelajahi artikel lainnya!

Dika Ardianta


More Posts

Comments