invoke with bin/jemalloc rails s
We weren’t using 3 before, but have been running 5 in prod for ~10 months now, we saw ~25% less memory usage compared to default malloc
see also https://gist.github.com/jjb/9ff0d3f622c8bbe904fe7a82e35152fc
invoke with bin/jemalloc rails s
We weren’t using 3 before, but have been running 5 in prod for ~10 months now, we saw ~25% less memory usage compared to default malloc
see also https://gist.github.com/jjb/9ff0d3f622c8bbe904fe7a82e35152fc
#!/usr/bin/env ruby | |
# frozen_string_literal: true | |
ENV['LD_PRELOAD'] = ENV['JEMALLOC_PATH'] | |
ENV['MALLOC_CONF'] = { | |
# Maximum number of arenas to use for automatic multiplexing of threads and arenas. | |
# The default is four times the number of CPUs, or one if there is a single CPU. | |
narenas: 2, | |
# Enabling jemalloc background threads generally improves the tail latency for application threads, | |
# since unused memory purging is shifted to the dedicated background threads. | |
# In addition, unintended purging delay caused by application inactivity is avoided with background threads. | |
# | |
# Suggested: background_thread:true when jemalloc managed threads can be allowed. | |
background_thread: true, | |
# Transparent hugepage (THP) mode. | |
# Settings "always", "never" and "default" are available if THP is supported by the operating system. | |
# The "always" setting enables transparent hugepage for all user memory mappings with MADV_HUGEPAGE; | |
# "never" ensures no transparent hugepage with MADV_NOHUGEPAGE; the default setting "default" makes no changes. | |
thp: 'never', | |
# Decay time determines how fast jemalloc returns unused pages back to the operating system, | |
# and therefore provides a fairly straightforward trade-off between CPU and memory usage. | |
# Shorter decay time purges unused pages faster to reduces memory usage | |
# (usually at the cost of more CPU cycles spent on purging), and vice versa. | |
# | |
# Suggested: tune the values based on the desired trade-offs. | |
dirty_decay_ms: 1_000, # Default 10_000 | |
muzzy_decay_ms: 0 # Default 10_000 | |
}.map { |conf| conf.join(':') }.join(',').freeze # Convert to a MALLOC_CONF string | |
require 'pathname' | |
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', | |
Pathname.new(__FILE__).realpath) | |
bundle_binstub = File.expand_path('bundle', __dir__) | |
if File.file?(bundle_binstub) | |
if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300)) | |
load(bundle_binstub) | |
else | |
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. | |
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") | |
end | |
end | |
require 'rubygems' | |
require 'bundler/setup' | |
arg = ARGV.shift | |
if arg.nil? | |
warn "Usage: #{$PROGRAM_NAME} executable_name" | |
warn "Usage: #{$PROGRAM_NAME} gem_name/executable_name" | |
exit(1) | |
end | |
# If the executable is the same as the gem, we can pass "executable_name" vs "gem_name/executable_name" | |
gem, executable = arg.split('/') | |
executable ||= gem | |
gem = 'railties' if gem == 'rails' # Rails has no executables, they're stored in railties | |
if gem.empty? | |
warn('Exiting: Must supply a gem bin or gem_name/executable') | |
exit(1) | |
end | |
load Gem.bin_path(gem, executable) |