Skip to content

Instantly share code, notes, and snippets.

@corporatepiyush
Last active August 28, 2024 08:58
Show Gist options
  • Save corporatepiyush/318c0c6970caee8af36360a8f5e2df4c to your computer and use it in GitHub Desktop.
Save corporatepiyush/318c0c6970caee8af36360a8f5e2df4c to your computer and use it in GitHub Desktop.
Memory optimisations using jemalloc and tcmalloc on Linux
#!/bin/bash
# File: /usr/local/bin/configure_malloc.sh
set_malloc_config() {
local total_ram=$1
local arena_max mmap_threshold trim_threshold top_pad
mmap_threshold=524288 # 512 KB
trim_threshold=524288 # 512 KB
if [ "$total_ram" -lt 8192 ]; then
arena_max=8
top_pad=32768 # 32 KB
elif [ "$total_ram" -lt 32768 ]; then
arena_max=16
top_pad=65536 # 64 KB
elif [ "$total_ram" -lt 65536 ]; then
arena_max=24
top_pad=131072 # 128 KB
else
arena_max=32
top_pad=524288 # 512 KB
fi
echo "$arena_max:$mmap_threshold:$trim_threshold:$top_pad"
}
update_environment_file() {
local env_file="/etc/environment"
local arena_max=$1
local mmap_threshold=$2
local trim_threshold=$3
local top_pad=$4
# Remove existing MALLOC and GLIBC_TUNABLES entries
sudo sed -i '/^MALLOC_/d' "$env_file"
sudo sed -i '/^GLIBC_TUNABLES/d' "$env_file"
# Append new entries
sudo tee -a "$env_file" > /dev/null << EOF
GLIBC_TUNABLES="glibc.malloc.arena_max=$arena_max:glibc.malloc.mmap_threshold=$mmap_threshold:glibc.malloc.trim_threshold=$trim_threshold:glibc.malloc.top_pad=$top_pad"
MALLOC_ARENA_MAX=$arena_max
MALLOC_MMAP_THRESHOLD_=$mmap_threshold
MALLOC_TRIM_THRESHOLD_=$trim_threshold
MALLOC_TOP_PAD_=$top_pad
MALLOC_MMAP_MAX_=2097152
MALLOC_CHECK_=0
MALLOC_PERTURB_=0
EOF
echo "Memory allocator configuration updated in $env_file"
}
# Get total RAM size in MB
total_ram=$(free -m | awk '/^Mem:/{print $2}')
# Get malloc configuration based on total RAM
IFS=':' read -r arena_max mmap_threshold trim_threshold top_pad <<< "$(set_malloc_config "$total_ram")"
# Update /etc/environment with new configuration
update_environment_file "$arena_max" "$mmap_threshold" "$trim_threshold" "$top_pad"
echo "Configuration complete. Changes will take effect after reboot or re-login."
echo "To apply changes to the current session, run: source /etc/environment"
grep -z 'LD_PRELOAD' /proc/<pid>/environ | tr '\0' '\n'
# if jemalloc is listed among the loaded libraries for a process.
lsof -p <pid> | grep jemalloc
# to list the shared libraries used by an executable
ldd /path/to/your/application | grep jemalloc
# Create a systemd override directory for MySQL
sudo mkdir -p /etc/systemd/system/mysql.service.d
# Create a systemd override file for MySQL
echo -e "[Service]\nEnvironment=\"LD_PRELOAD=/usr/local/lib/libjemalloc.so\"\nEnvironment=\"MALLOC_CONF='dirty_decay_ms:1000,narenas:2,background_thread:true'\"" | sudo tee /etc/systemd/system/mysqld.service.d/override.conf
# Reload systemd and restart MySQL
sudo systemctl daemon-reload
sudo systemctl restart mysql
# Set jemalloc as the default allocator and MALLOC_ARENA_MAX=2 at the OS level
echo 'export LD_PRELOAD=/usr/local/lib/libjemalloc.so' | sudo tee -a /etc/profile.d/jemalloc.sh
echo "export MALLOC_CONF='dirty_decay_ms:1000,narenas:2,background_thread:true'" | sudo tee -a /etc/profile.d/jemalloc.sh
# Make the script executable
sudo chmod +x /etc/profile.d/jemalloc.sh
# Apply the environment variables immediately
source /etc/profile.d/jemalloc.sh
# Create a systemd override directory for PostgreSQL
sudo mkdir -p /etc/systemd/system/postgresql.service.d
# Create a systemd override file for PostgreSQL
echo -e "[Service]\nEnvironment=\"LD_PRELOAD=/usr/local/lib/libjemalloc.so\"\nEnvironment=\"MALLOC_CONF='dirty_decay_ms:1000,narenas:2,background_thread:true'\"" | sudo tee /etc/systemd/system/postgresql.service.d/override.conf
# Reload systemd and restart PostgreSQL
sudo systemctl daemon-reload
sudo systemctl restart postgresql
# Add LD_PRELOAD to .bashrc
echo 'export LD_PRELOAD=/usr/local/lib/libjemalloc.so' >> ~/.bashrc
echo "export MALLOC_CONF='dirty_decay_ms:1000,narenas:2,background_thread:true'" >> ~/.bashrc
# Reload .bashrc to apply changes
source ~/.bashrc
# Add LD_PRELOAD to .bashrc
echo 'export LD_PRELOAD=/usr/local/lib/libjemalloc.so' >> ~/.zshrc
echo "export MALLOC_CONF='dirty_decay_ms:1000,narenas:2,background_thread:true'" >> ~/.zshrc
# Reload .zshrc to apply changes
source ~/.zshrc
#!/bin/bash
# Update package lists
sudo apt-get update
sudo apt-get upgrade
# Install dependencies
sudo apt-get install -y autoconf automake libtool make gcc
# Download jemalloc source code
JEMALLOC_VERSION=5.3.0
wget https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/jemalloc-${JEMALLOC_VERSION}.tar.bz2
# Extract the downloaded tarball
tar -xvf jemalloc-${JEMALLOC_VERSION}.tar.bz2
# Change to the extracted directory
cd jemalloc-${JEMALLOC_VERSION}
# Compile and install jemalloc
./autogen.sh
make
sudo make install
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status
set -u # Treat unset variables as an error
# Function to log messages
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
# Function to handle errors
error_exit() {
log "ERROR: $1" >&2
exit 1
}
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to install TCMalloc
install_tcmalloc() {
log "Installing TCMalloc..."
if ! command_exists apt-get; then
error_exit "apt-get not found. This script requires a Debian-based system."
fi
sudo apt-get update || error_exit "Failed to update package list"
sudo apt-get install -y google-perftools || error_exit "Failed to install google-perftools"
}
# Function to find TCMalloc library
find_tcmalloc_lib() {
log "Finding TCMalloc library..."
TCMALLOC_LIB=$(ldconfig -p | grep libtcmalloc.so | awk '{print $4}' | head -n 1)
if [ -z "$TCMALLOC_LIB" ]; then
error_exit "libtcmalloc.so not found. Please check your installation."
fi
log "Found TCMalloc library at: $TCMALLOC_LIB"
}
# Function to set TCMalloc parameters based on RAM
set_tcmalloc_params() {
log "Setting TCMalloc parameters..."
total_ram_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
total_ram_gb=$((total_ram_kb / 1024 / 1024))
# Default values
aggressive_decommit=false
release_rate=0.1
large_alloc_threshold=4294967296
# RAM-based configuration
if [ $total_ram_gb -le 8 ]; then
max_total_thread_cache_bytes=268435456 # 256 MB
transfer_batch_size=128
elif [ $total_ram_gb -le 16 ]; then
max_total_thread_cache_bytes=536870912 # 512 MB
transfer_batch_size=256
elif [ $total_ram_gb -le 32 ]; then
max_total_thread_cache_bytes=1073741824 # 1 GB
transfer_batch_size=512
else
max_total_thread_cache_bytes=4294967296 # 4 GB
transfer_batch_size=1024
fi
log "TCMalloc parameters set based on ${total_ram_gb}GB RAM"
}
# Function to update shell configuration files
update_shell_config() {
local config_file="$1"
log "Updating $config_file with TCMalloc settings..."
# Check if the config file exists
if [ ! -f "$config_file" ]; then
touch "$config_file"
fi
# Remove any existing TCMalloc configuration
sed -i '/# TCMalloc configuration/,/# End TCMalloc configuration/d' "$config_file"
# Append new TCMalloc configuration
cat << EOF >> "$config_file"
# TCMalloc configuration
export LD_PRELOAD='$TCMALLOC_LIB'
export TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD=$large_alloc_threshold
export TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=$max_total_thread_cache_bytes
export TCMALLOC_AGGRESSIVE_DECOMMIT=$aggressive_decommit
export TCMALLOC_TRANSFER_BATCH_SIZE=$transfer_batch_size
export TCMALLOC_RELEASE_RATE=$release_rate
# End TCMalloc configuration
EOF
log "$config_file updated successfully."
}
# Function to update all relevant shell configuration files
update_shell_configs() {
update_shell_config "$HOME/.bashrc"
if command_exists zsh; then
update_shell_config "$HOME/.zshrc"
fi
}
# Function to verify the configuration
verify_configuration() {
log "Verifying TCMalloc configuration..."
if [ -z "${LD_PRELOAD:-}" ]; then
log "WARNING: LD_PRELOAD is not set in the current session."
log "Please run 'source ~/.bashrc' (for Bash) or 'source ~/.zshrc' (for Zsh)"
log "or start a new terminal session to apply the changes."
else
log "LD_PRELOAD is set to: $LD_PRELOAD"
fi
}
# Main execution
main() {
log "Starting TCMalloc configuration script..."
install_tcmalloc
find_tcmalloc_lib
set_tcmalloc_params
update_shell_configs
verify_configuration
log "TCMalloc configuration completed successfully."
log "To apply changes immediately, run: source ~/.bashrc (for Bash) or source ~/.zshrc (for Zsh)"
}
# Run the main function
main
@corporatepiyush
Copy link
Author

sudo reboot also helpful

@mokshchadha
Copy link

mokshchadha commented May 24, 2024

very helpful script

@mokshchadha
Copy link

To make sure you are using the correct path for your jemalloc lib file one can use

find /usr -name "libjemalloc.so*"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment