はじめに
小ネタで恐縮ですが、jemallocをHerokuのRubyで有効にしたあとで、それを確認する方法をやっと見つけました。
jemallocは、メモリアロケータとして昔から使われているmallocの改良版ですが、jemallocを有効にするにはRubyをビルドするときに指定する必要があります。
Rubyは、デフォルトではjemallocではなく従来のmallocを使ってビルドするようになっています。jemallocについて詳しくは以下の記事をご覧ください。
なお、Rails 7.2から新規アプリのDockerfileにデフォルトでjemallocが使われます(ウォッチ20240221)。
The answer to every Ruby memory usage problem is "have you tried jemalloc yet?"
— Nate Berkopec (@nateberkopec) August 28, 2023
heroku-buildpack-jemalloc
以下のheroku-buildpack-jemallocを使うと、Herokuでjemallocを有効にできます。
設定方法
参考: gaffneyc/heroku-buildpack-jemalloc - Buildpacks - Heroku Elements
上のヘルプに沿って設定できますが、せっかくなので本題に入る前にメモしておきます。以下、既にRailsアプリがHerokuにデプロイ済みであることが前提です
最初に、heroku-buildpack-jemallocをインストールします。
Heroku CLIが有効なローカル環境で以下を実行します。
heroku buildpacks:add --index 1 https://github.com/gaffneyc/heroku-buildpack-jemalloc.git
git push heroku master
今回は使いませんでしたが、Heroku GUIダッシュボードのbuildpackでもheroku-buildpack-jemallocをインストールできるはずです。なお、heroku-buildpack-jemallocは無料で使えます。
続いて、以下のいずれかの方法でjemallocを有効にします。
- Herokuでグローバルに設定したい場合は、環境変数
JEMALLOC_ENABLED=true
を設定する - Herokuのdynoごとに設定する場合は、Railsの
Procfile
にweb: jemalloc.sh bundle exec puma -C config/puma.rb
を記述する
念のため、JEMALLOC_VERSION= 5.3.0
環境変数でjemallocのバージョンも指定しました。
jemallocが有効になったかどうかを確かめる方法
これが本題です。
これまで自分の記事を参考に、Herokuにheroku run bash --app アプリ名
でログインしてからirb -r rbconfig
でIRBを起動し、RbConfig::CONFIG['MAINLIBS']
を実行する形で確認していたのですが、ちっとも-ljemalloc
の文字が表示されませんでした。
$ heroku run bash --app XXX
Running bash on ⬢ XXX... up, run.2078 (Basic)
~ $ irb -r rbconfig
irb(main):001> RbConfig::CONFIG['MAINLIBS']
=> "-lz -lrt -lrt -lgmp -ldl -lcrypt -lm -lpthread " # -ljemallocが表示されない...
しかし同リポジトリのissueに正しい確認方法が掲載されていました↓。RbConfig::CONFIG['MAINLIBS']
で確認できるかと思ったら、できないんですね🫠。
参考: How to validate buildpack is having an effect · Issue #5 · gaffneyc/heroku-buildpack-jemalloc
上と同じ方法でHerokuにログインしてから、MALLOC_CONF=stats_print:true ruby -e "exit"
を実行します。以下のような情報が出力されたらjemallocは有効、何も出力せずに終了したら無効です。
$ MALLOC_CONF=stats_print:true ruby -e "exit"
___ Begin jemalloc statistics ___
Version: "5.3.0-0-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c"
Build-time option settings
config.cache_oblivious: true
config.debug: false
config.fill: true
config.lazy_lock: false
config.malloc_conf: ""
config.opt_safety_checks: false
config.prof: false
config.prof_libgcc: false
config.prof_libunwind: false
config.stats: true
config.utrace: false
config.xmalloc: false
Run-time option settings
opt.abort: false
opt.abort_conf: false
opt.cache_oblivious: true
opt.confirm_conf: false
opt.retain: true
opt.dss: "secondary"
opt.narenas: 32
opt.percpu_arena: "disabled"
opt.oversize_threshold: 8388608
opt.hpa: false
opt.hpa_slab_max_alloc: 65536
opt.hpa_hugification_threshold: 1992294
opt.hpa_hugify_delay_ms: 10000
opt.hpa_min_purge_interval_ms: 5000
opt.hpa_dirty_mult: "0.25"
opt.hpa_sec_nshards: 4
opt.hpa_sec_max_alloc: 32768
opt.hpa_sec_max_bytes: 262144
opt.hpa_sec_bytes_after_flush: 131072
opt.hpa_sec_batch_fill_extra: 0
opt.metadata_thp: "disabled"
opt.mutex_max_spin: 600
opt.background_thread: false (background_thread: false)
opt.dirty_decay_ms: 10000 (arenas.dirty_decay_ms: 10000)
opt.muzzy_decay_ms: 0 (arenas.muzzy_decay_ms: 0)
opt.lg_extent_max_active_fit: 6
opt.junk: "false"
opt.zero: false
opt.experimental_infallible_new: false
opt.tcache: true
opt.tcache_max: 32768
opt.tcache_nslots_small_min: 20
opt.tcache_nslots_small_max: 200
opt.tcache_nslots_large: 20
opt.lg_tcache_nslots_mul: 1
opt.tcache_gc_incr_bytes: 65536
opt.tcache_gc_delay_bytes: 0
opt.lg_tcache_flush_small_div: 1
opt.lg_tcache_flush_large_div: 1
opt.thp: "not supported"
opt.stats_print: true
opt.stats_print_opts: ""
opt.stats_print: true
opt.stats_print_opts: ""
opt.stats_interval: -1
opt.stats_interval_opts: ""
opt.zero_realloc: "free"
Arenas: 33
Quantum size: 16
Page size: 4096
Maximum thread-cached size class: 32768
Number of bin size classes: 36
Number of thread-cache bin size classes: 41
Number of large size classes: 196
Allocated: 3923720, active: 4382720, metadata: 3689200 (n_thp 0), resident: 13570048, mapped: 16261120, retained: 1564672
Count of realloc(non-null-ptr, 0) calls: 0
Background threads: 0, num_runs: 0, run_interval: 0 ns
n_lock_ops (#/sec) n_waiting (#/sec) n_spin_acq (#/sec) n_owner_switch (#/sec) total_wait_ns (#/sec) max_wait_ns max_n_thds
background_thread 4 4 0 0 0 0 1 1 0 0 0 0
max_per_bg_thd 0 0 0 0 0 0 0 0 0 0 0 0
ctl 2 2 0 0 0 0 1 1 0 0 0 0
prof 0 0 0 0 0 0 0 0 0 0 0 0
prof_thds_data 0 0 0 0 0 0 0 0 0 0 0 0
prof_dump 0 0 0 0 0 0 0 0 0 0 0 0
prof_recent_alloc 0 0 0 0 0 0 0 0 0 0 0 0
prof_recent_dump 0 0 0 0 0 0 0 0 0 0 0 0
prof_stats 0 0 0 0 0 0 0 0 0 0 0 0
arenas[0]:
assigned threads: 1
uptime: 55999808
dss allocation precedence: "secondary"
decaying: time npages sweeps madvises purged
dirty: 10000 1364 0 0 0
muzzy: 0 0 0 0 0
allocated nmalloc (#/sec) ndalloc (#/sec) nrequests (#/sec) nfill (#/sec) nflush (#/sec)
small: 2338568 28477 28477 8744 8744 58042 58042 655 655 325 325
large: 1585152 250 250 239 239 407 407 250 250 14 14
total: 3923720 28727 28727 8983 8983 58449 58449 905 905 339 339
active: 4382720
mapped: 16261120
retained: 1564672
base: 3594992
internal: 94208
metadata_thp: 0
tcache_bytes: 325640
tcache_stashed_bytes: 0
resident: 13570048
abandoned_vm: 0
extent_avail: 2
n_lock_ops (#/sec) n_waiting (#/sec) n_spin_acq (#/sec) n_owner_switch (#/sec) total_wait_ns (#/sec) max_wait_ns max_n_thds
large 2 2 0 0 0 0 1 1 0 0 0 0
extent_avail 732 732 0 0 0 0 1 1 0 0 0 0
extents_dirty 1069 1069 0 0 0 0 1 1 0 0 0 0
extents_muzzy 2 2 0 0 0 0 1 1 0 0 0 0
extents_retained 280 280 0 0 0 0 1 1 0 0 0 0
decay_dirty 15 15 0 0 0 0 1 1 0 0 0 0
decay_muzzy 2 2 0 0 0 0 1 1 0 0 0 0
base 414 414 0 0 0 0 1 1 0 0 0 0
tcache_list 4 4 0 0 0 0 1 1 0 0 0 0
hpa_shard 0 0 0 0 0 0 0 0 0 0 0 0
hpa_shard_grow 0 0 0 0 0 0 0 0 0 0 0 0
hpa_sec 0 0 0 0 0 0 0 0 0 0 0 0
bins: size ind allocated nmalloc (#/sec) ndalloc (#/sec) nrequests (#/sec) nshards curregs curslabs nonfull_slabs regs pgs util nfills (#/sec) nflushes (#/sec) nslabs nreslabs (#/sec) n_lock_ops (#/sec) n_waiting (#/sec) n_spin_acq (#/sec) n_owner_switch (#/sec) total_wait_ns (#/sec) max_wait_ns max_n_thds
8 0 10584 1775 1775 452 452 2265 2265 1 1323 3 1 512 1 0.861 26 26 10 10 3 2 2 42 42 0 0 0 0 1 1 0 0 0 0
16 1 39744 3275 3275 791 791 4778 4778 1 2484 10 0 256 1 0.970 35 35 10 10 11 12 12 59 59 0 0 0 0 1 1 0 0 0 0
32 2 188800 9100 9100 3200 3200 14549 14549 1 5900 48 4 128 1 0.960 91 91 32 32 54 111 111 180 180 0 0 0 0 1 1 0 0 0 0
48 3 198624 4850 4850 712 712 9962 9962 1 4138 17 0 256 3 0.950 55 55 9 9 17 14 14 84 84 0 0 0 0 1 1 0 0 0 0
64 4 71168 1344 1344 232 232 6600 6600 1 1112 18 0 64 1 0.965 29 29 7 7 19 23 23 58 58 0 0 0 0 1 1 0 0 0 0
80 5 27360 457 457 115 115 1349 1349 1 342 2 0 256 5 0.667 18 18 8 8 2 2 2 31 31 0 0 0 0 1 1 0 0 0 0
96 6 55296 900 900 324 324 1744 1744 1 576 5 0 128 3 0.900 14 14 8 8 8 9 9 33 33 0 0 0 0 1 1 0 0 0 0
112 7 20048 266 266 87 87 367 367 1 179 1 0 256 7 0.699 12 12 8 8 1 0 0 24 24 0 0 0 0 1 1 0 0 0 0
128 8 51968 504 504 98 98 1097 1097 1 406 13 0 32 1 0.975 25 25 7 7 13 14 14 48 48 0 0 0 0 1 1 0 0 0 0
160 9 86400 750 750 210 210 1996 1996 1 540 5 0 128 5 0.843 11 11 7 7 6 1 1 27 27 0 0 0 0 1 1 0 0 0 0
192 10 33600 274 274 99 99 337 337 1 175 3 1 64 3 0.911 10 10 7 7 3 2 2 23 23 0 0 0 0 1 1 0 0 0 0
224 11 36512 362 362 199 199 371 371 1 163 2 0 128 7 0.636 9 9 9 9 3 5 5 24 24 0 0 0 0 1 1 0 0 0 0
256 12 73984 310 310 21 21 700 700 1 289 19 0 16 1 0.950 27 27 5 5 20 3 3 55 55 0 0 0 0 1 1 0 0 0 0
320 13 41280 160 160 31 31 282 282 1 129 3 0 64 5 0.671 9 9 7 7 3 0 0 22 22 0 0 0 0 1 1 0 0 0 0
384 14 491904 2480 2480 1199 1199 2813 2813 1 1281 41 0 32 3 0.976 83 83 39 39 59 53 53 184 184 0 0 0 0 1 1 0 0 0 0
448 15 26432 126 126 67 67 125 125 1 59 1 0 64 7 0.921 11 11 8 8 1 0 0 23 23 0 0 0 0 1 1 0 0 0 0
512 16 101888 207 207 8 8 457 457 1 199 25 0 8 1 0.995 33 33 5 5 27 3 3 68 68 0 0 0 0 1 1 0 0 0 0
640 17 77440 576 576 455 455 6541 6541 1 121 6 2 32 5 0.630 26 26 18 18 7 30 30 54 54 0 0 0 0 1 1 0 0 0 0
768 18 35328 76 76 30 30 144 144 1 46 4 1 16 3 0.718 8 8 6 6 5 4 4 22 22 0 0 0 0 1 1 0 0 0 0
896 19 32256 92 92 56 56 107 107 1 36 2 1 32 7 0.562 8 8 7 7 2 1 1 20 20 0 0 0 0 1 1 0 0 0 0
1024 20 57344 106 106 50 50 315 315 1 56 18 7 4 1 0.777 15 15 9 9 25 7 7 52 52 0 0 0 0 1 1 0 0 0 0
1280 21 26880 60 60 39 39 271 271 1 21 3 2 16 5 0.437 10 10 9 9 3 5 5 25 25 0 0 0 0 1 1 0 0 0 0
1536 22 38400 77 77 52 52 117 117 1 25 5 3 8 3 0.625 12 12 10 10 8 7 7 33 33 0 0 0 0 1 1 0 0 0 0
1792 23 55552 76 76 45 45 67 67 1 31 3 1 16 7 0.645 9 9 9 9 4 1 1 25 25 0 0 0 0 1 1 0 0 0 0
2048 24 65536 52 52 20 20 149 149 1 32 16 0 2 1 1 10 10 8 8 24 6 6 45 45 0 0 0 0 1 1 0 0 0 0
2560 25 20480 24 24 16 16 23 23 1 8 2 1 8 5 0.500 8 8 8 8 4 4 4 23 23 0 0 0 0 1 1 0 0 0 0
3072 26 27648 23 23 14 14 31 31 1 9 3 1 4 3 0.750 8 8 6 6 5 2 2 22 22 0 0 0 0 1 1 0 0 0 0
3584 27 14336 20 20 16 16 10 10 1 4 1 0 8 7 0.500 5 5 6 6 3 1 1 17 17 0 0 0 0 1 1 0 0 0 0
4096 28 57344 31 31 17 17 59 59 1 14 14 0 1 1 1 7 7 5 5 31 0 0 46 46 0 0 0 0 1 1 0 0 0 0
5120 29 25600 17 17 12 12 22 22 1 5 2 0 4 5 0.625 6 6 6 6 5 3 3 20 20 0 0 0 0 1 1 0 0 0 0
6144 30 49152 30 30 22 22 18 18 1 8 5 2 2 3 0.800 8 8 7 7 15 6 6 33 33 0 0 0 0 1 1 0 0 0 0
7168 31 7168 12 12 11 11 2 2 1 1 1 0 4 7 0.250 2 2 4 4 3 1 1 12 12 0 0 0 0 1 1 0 0 0 0
8192 32 114688 27 27 13 13 77 77 1 14 14 0 1 2 1 6 6 6 6 27 0 0 42 42 0 0 0 0 1 1 0 0 0 0
10240 33 40960 10 10 6 6 281 281 1 4 2 0 2 5 1 1 1 2 2 5 1 1 11 11 0 0 0 0 1 1 0 0 0 0
12288 34 36864 16 16 13 13 12 12 1 3 3 0 1 3 1 5 5 8 8 16 0 0 32 32 0 0 0 0 1 1 0 0 0 0
14336 35 0 12 12 12 12 4 4 1 0 0 0 2 7 1 3 3 5 5 7 2 2 18 18 0 0 0 0 1 1 0 0 0 0
large: size ind allocated nmalloc (#/sec) ndalloc (#/sec) nrequests (#/sec) curlextents
16384 36 16384 4 4 3 3 6 6 1
20480 37 40960 4 4 2 2 158 158 2
24576 38 24576 3 3 2 2 4 4 1
28672 39 28672 1 1 0 0 1 1 1
32768 40 32768 3 3 2 2 3 3 1
40960 41 0 128 128 128 128 128 128 0
49152 42 49152 2 2 1 1 2 2 1
---
65536 44 65536 3 3 2 2 3 3 1
81920 45 81920 54 54 53 53 54 54 1
98304 46 0 1 1 1 1 1 1 0
---
163840 49 0 24 24 24 24 24 24 0
196608 50 196608 1 1 0 0 1 1 1
---
327680 53 0 13 13 13 13 13 13 0
393216 54 0 1 1 1 1 1 1 0
---
655360 57 0 4 4 4 4 4 4 0
---
1048576 60 1048576 1 1 0 0 1 1 1
1310720 61 0 2 2 2 2 2 2 0
---
2621440 65 0 1 1 1 1 1 1 0
---
extents: size ind ndirty dirty nmuzzy muzzy nretained retained ntotal total
4096 0 14 57344 0 0 0 0 14 57344
8192 1 3 24576 0 0 0 0 3 24576
12288 2 3 36864 0 0 0 0 3 36864
16384 3 1 16384 0 0 0 0 1 16384
20480 4 2 40960 0 0 0 0 2 40960
24576 5 2 49152 0 0 0 0 2 49152
28672 6 1 28672 0 0 0 0 1 28672
---
81920 12 1 73728 0 0 0 0 1 73728
98304 13 1 94208 0 0 0 0 1 94208
---
229376 18 1 229376 0 0 0 0 1 229376
---
458752 22 1 397312 0 0 0 0 1 397312
524288 23 1 475136 0 0 1 520192 2 995328
---
1048576 27 0 0 0 0 1 1044480 1 1044480
---
1572864 29 1 1437696 0 0 0 0 1 1437696
---
3145728 33 1 2625536 0 0 0 0 1 2625536
---
Bytes in small extent cache: 0
HPA shard stats:
Purge passes: 0 (0 / sec)
Purges: 0 (0 / sec)
Hugeifies: 0 (0 / sec)
Dehugifies: 0 (0 / sec)
In full slabs:
npageslabs: 0 huge, 0 nonhuge
nactive: 0 huge, 0 nonhuge
ndirty: 0 huge, 0 nonhuge
nretained: 0 huge, 0 nonhuge
In empty slabs:
npageslabs: 0 huge, 0 nonhuge
nactive: 0 huge, 0 nonhuge
ndirty: 0 huge, 0 nonhuge
nretained: 0 huge, 0 nonhuge
size ind npageslabs_huge nactive_huge ndirty_huge npageslabs_nonhuge nactive_nonhuge ndirty_nonhuge nretained_nonhuge
---
--- End jemalloc statistics ---
というわけでやっとjemallocが有効になりました。