Optimizing Project Zomboid Memory and UDP Ports via LinuxGSM
Project Zomboid runs on a custom Java engine that, while charming, has a famously aggressive memory footprint once a horde event spawns several thousand active zombies inside loaded cells. The default 2 GB heap will stall the world thread within minutes. This guide stands up a hardened LinuxGSM deployment on Ubuntu 24.04, opens both required UDP ports, and tunes the G1 garbage collector to absorb sustained horde pressure without pauses long enough to drop client connections.
Prerequisites
- Ubuntu 24.04 LTS with at least 8 GB of RAM and a 4 core CPU.
- A non root user with sudo access (LinuxGSM refuses to run as root).
- UDP 16261 (game) and UDP 16262 (steam channel) open at the firewall.
- At least 20 GB of free disk for the SteamCMD download and persistent saves.
Step 1: System Preparation
sudo adduser --disabled-password --gecos "" pzusersudo dpkg --add-architecture i386sudo apt updatesudo apt install -y curl wget file tar bzip2 gzip unzip bsdmainutils \ python3 util-linux ca-certificates binutils bc jq tmux netcat-openbsd \ lib32gcc-s1 lib32stdc++6 libsdl2-2.0-0:i386 openjdk-17-jre-headlessStep 2: Install LinuxGSM and the Server
sudo machinectl shell pzuser@cd ~wget -O linuxgsm.sh https://linuxgsm.shchmod +x linuxgsm.shbash linuxgsm.sh pzserver./pzserver installStep 3: Open the Dual UDP Ports
Zomboid uses two UDP ports, and a common misconfiguration is to forward only 16261. Without 16262 open, the steam channel handshake fails and clients hang on the connecting screen with no log line on the server side.
sudo ufw allow 16261/udpsudo ufw allow 16262/udpsudo ufw reloadStep 4: Tune the JVM for Horde Events
Edit the JVM arguments file to switch from the default parallel collector to G1, raise the heap to a host appropriate ceiling, and pin MaxGCPauseMillis low enough that the game loop never stalls past a tick.
startparameters="-Xms6g -Xmx6g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=50 \ -XX:+ParallelRefProcEnabled \ -XX:+AlwaysPreTouch \ -XX:+UnlockExperimentalVMOptions \ -Dzomboid.steamport=16261 \ -Dzomboid.znetlog=1 \ -- -cachedir=/home/pzuser/Zomboid"Step 5: Automated World Saves
crontab -e0 */2 * * * /home/pzuser/pzserver send "save"30 4 * * * /home/pzuser/pzserver send "quit"35 4 * * * /home/pzuser/pzserver startPerformance and Tuning
- Match
-Xmsand-Xmxto lock the heap and avoid resize pauses. - Leave at least 1.5 GB of host RAM headroom outside the JVM for the OS page cache.
- Lower
MaxGCPauseMillisbelow 50 only if you are also seeing player rubber banding, not because lower looks better.
Conclusion
A correctly tuned Zomboid server with both UDP ports exposed, a G1 garbage collector tuned for tight pauses, and a cron driven save loop will survive the worst horde events your community can engineer.