Minecraft 服务端 JVM 调优指南(低资源 / 非专用服务器专用)

Minecraft 服务端 JVM 调优指南(低资源 / 非专用服务器专用)

写在前面

这份文档专门针对资源非常有限的 Minecraft 服务端(典型配置:2核4G、4核8G VPS/独立小服务器、甚至更低的共享主机),目标是:在内存紧张、CPU 核心数不多的情况下,尽可能让服务器 TPS 稳定、长尾延迟可控,避免频繁卡顿或被系统杀掉。

适用前提:

  • 服务器不是高配专用物理机或云大内存实例(8核16G+、甚至更高)
  • Java 版本最好是 Java 25,至少是 java21

这份调优的核心思路是:

  1. 极致放大 Eden + 快速晋升老年代(压缩 Survivor + 极低 TenuringThreshold)
  2. 非常激进的并发标记启动阈值(IHOP 15--20)
  3. 更积极的 Mixed GC(降低活对象阈值、增加混合回收次数)
  4. 非专用机必须考虑内存归还(SoftMax + 周期性 GC + 激进收缩)

这些改动在小堆、低核环境下能显著降低 50--200ms 级别的长尾停顿,让 tick 更稳定,但也会牺牲一部分 GC 吞吐和平均性能------这正是低资源 MC 必须做的取舍。

这份配置不适合高配服务器。如果服务器有 8G+ 内存、多核 CPU,直接用 ZGC 默认配置通常更好,没必要在 G1 上抠这么多参数

G1GC 配置(推荐用于 2G+ 内存)

文档参数基于 Java 25,java21 去掉 UseCompactObjectHeaders 即可

非专用服务器

bash 复制代码
#!/bin/bash
java -Xms512M \
     -Xmx2500M \
     -XX:SoftMaxHeapSize=1500M \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:G1ReservePercent=20 \
     -XX:G1MixedGCCountTarget=4 \
     -XX:+DisableExplicitGC \
     -XX:+UseStringDeduplication \
     -XX:+UseCompactObjectHeaders \
     -XX:G1PeriodicGCInterval=60000 \
     -XX:MaxHeapFreeRatio=30 \
     -XX:MinHeapFreeRatio=10 \
     -XX:-ShrinkHeapInSteps \
     -XX:SurvivorRatio=32 \
     -XX:MaxTenuringThreshold=1 \
     -XX:InitiatingHeapOccupancyPercent=20 \
     -XX:+UnlockExperimentalVMOptions \
     -XX:G1NewSizePercent=30 \
     -XX:G1MaxNewSizePercent=40 \
     -jar java.jar 

mc 专用服务器

bash 复制代码
#!/bin/bash
java -Xms2500M \
     -Xmx2500M \
     -XX:+AlwaysPreTouch \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:G1ReservePercent=20 \
     -XX:G1MixedGCCountTarget=4 \
     -XX:+DisableExplicitGC \
     -XX:+UseStringDeduplication \
     -XX:+UseCompactObjectHeaders \
     -XX:SurvivorRatio=32 \
     -XX:MaxTenuringThreshold=1 \
     -XX:InitiatingHeapOccupancyPercent=20 \
     -XX:+UnlockExperimentalVMOptions \
     -XX:G1NewSizePercent=30 \
     -XX:G1MaxNewSizePercent=40 \
     -jar java.jar

Serial GC 配置(适用于极小内存)

对于 1G 左右的堆内存,Serial GC 比 G1 更合适,因为堆不大停顿时间几乎没有区别

不过这个堆大小运行 mc 稍微有点吃力了

bash 复制代码
#!/bin/bash
java \
  -Xms1000M \
  -Xmx1000M \
  -XX:+UseSerialGC \
  -XX:+UseCompactObjectHeaders \
  -XX:NewRatio=1 \
  -XX:SurvivorRatio=32 \
  -jar java.jar

调优详解

调优目标

以 2核4g 的机器为例

MC 是 java 应用里极其少见的大型实时游戏服务端,对象分配速率非常高,同时又要求 tick 稳定、长尾延迟尽量低。在资源受限的前提下,首要目标是控制内存占用,其次是压低延迟抖动。

GC 选择上,堆不大、核心数也不多。Parallel GC 在小堆下虽然吞吐不错,但停顿不可预测,而且并行度在 2 核机器上发挥空间有限;Serial GC 停顿过长,不适合实时场景。MC 主线程基本吃满一个核心,反而给并发 GC 留出了一定余量,因此用 G1 在这个场景下更容易在延迟和资源之间取得平衡。ZGC 从模型上看确实很契合"高分配速率 + 低延迟"的特征,但在 2~3G 级别的小堆上收益有限,额外的元数据开销和并发成本反而不划算。

对象生命周期结构上,MC 和典型 Web 应用差异明显。普通后端应用通常是"极短命对象占大头,真正长寿对象数量少但存活时间很长,接近常驻"。而 MC 是:短命对象很多,真正常驻的对象反而不多,中间夹着大量"中等寿命对象"------可能存活几十秒到几十分钟。从 GC 视角看,这些已经属于长寿对象,但在业务层面并不是常驻。

在 G1 默认策略下,这些中等寿命对象会在 Survivor 区多次复制,增加 Young GC 的停顿时间;等它们陆续晋升到老年代后,如果并发标记和 Mixed GC 的节奏偏保守,又会出现老年代回收跟不上对象自然死亡节奏的问题,导致老年代占用上升、Mixed 次数增加,甚至触发更重的停顿。

因此调优思路的核心是:放大 Eden,尽量压缩 Survivor,让对象尽快结束在年轻代内部的反复搬运;同时降低 IHOP 等阈值,让并发标记更早开始,Mixed GC 更积极,保证老年代的清理速度能够跟上中等寿命对象的产生与死亡节奏。整体上是用更多 Eden 空间换更少的复制成本,再用更激进的老年代回收策略来维持堆的动态平衡,从而在有限内存下尽量压低长尾停顿。

GC 选择

指定 G1GC:

bash 复制代码
-XX:+UseG1GC

内存优化

为了节省内存:

bash 复制代码
-Xms512M                    # 初始内存
-Xmx2500M                   # 最大内存,防止 OOM
-XX:SoftMaxHeapSize=1500M   # 软上限,防止服务器其他服务(尤其是某些需要占用一定内存的定时任务)运行时内存不足导致 MC 被杀
-XX:+UseCompactObjectHeaders # 开启压缩对象头,MC 有很多小对象,该参数预计可以省下 5% 左右的内存
-XX:+UseStringDeduplication  # 开启重复字符串合并,MC 有很多相同的字符串
-XX:G1PeriodicGCInterval=60000  # 每 60 秒检测一次,如果 JVM 空闲就触发一次并发 GC 并归还内存
-XX:MaxHeapFreeRatio=30         # 堆缩容阈值
-XX:MinHeapFreeRatio=10         # 堆扩容阈值
-XX:-ShrinkHeapInSteps          # 禁用分步缩容,堆空闲时一次性缩到位而非分多步缓慢收缩(内存归还更加积极)

注意上述参数为了让 java 服务积极归还内存是牺牲了一定的稳定性的,如果是专用服务器建议修改为

bash 复制代码
-Xms2500M                   # 初始内存,保持和最大内存一致
-Xmx2500M                   # 最大内存,这个参数给元空间等非堆空间及系统保留了较高的余量,若内存占用长期稳定可考虑调大
-XX:+UseCompactObjectHeaders # 开启压缩对象头,MC 有很多小对象,该参数预计可以省下 5% 左右的内存
-XX:+UseStringDeduplication  # 开启重复字符串合并,MC 有很多相同的字符串
-XX:+AlwaysPreTouch          # 启动时初始化内存页,避免内存申请时抖动

延迟优化

为了稳定长尾延迟:

bash 复制代码
-XX:MaxGCPauseMillis=200              # 最大暂停时间(理论上这个值在mc上应该为50以下,但是不要在低资源服务器强行降低这个值)专用服务器可以调小这个值到150-180
-XX:G1ReservePercent=20               # 预留 20% 的堆作为缓冲,MC 负载波动大需要较为激进的缓冲(默认 10%),为了避免内存浪费可以适当调小这个值
-XX:G1MixedGCCountTarget=4            # 混合回收次数,这里更多的是个经验值(默认 8)
-XX:+DisableExplicitGC                # 禁止代码中调用 System.gc(),某些 mod 或插件代码写的不好

快速收敛优化

为了快速收敛(MC 负载恒定,设置如下参数可以使 G1 快速收敛到最佳状态):

bash 复制代码
-XX:InitiatingHeapOccupancyPercent=20 # 并发标记阈值,MC 对象分配快且有很多"中等寿命"的对象,需要较为激进的并发标记阈值(默认 45)这在低cpu核心数时是最关键的 tradeoff 参数,过低会导致并发标记频繁抢占 CPU,核心多可以调小这个值到15左右
-XX:+UnlockExperimentalVMOptions  # G1NewSizePercent G1MaxNewSizePercent 不是个正式特性,需要显式打开实验性参数
-XX:G1NewSizePercent=30           # 新生代最小大小,防止初始堆eden被击穿
-XX:G1MaxNewSizePercent=40        # 新生代最大大小,防止老年代被挤压

特殊调优

bash 复制代码
-XX:SurvivorRatio=32        # Eden 与 Survivor 比例,Survivor会被很快晋升不需要太大
-XX:MaxTenuringThreshold=1  # Survivor晋升老年代阈值,确保Survivor不被反复复制
相关推荐
廋到被风吹走2 小时前
稳定性保障:限流降级深度解析 —— Sentinel滑动窗口算法与令牌桶实现
运维·算法·sentinel
西西学代码2 小时前
Flutter---简单画板应用
服务器·数据库·flutter
一只程序熊2 小时前
uniappx richtext img 图片无法显示
linux·服务器·数据库
女王大人万岁2 小时前
Golang实战Eclipse Paho MQTT库:MQTT通信全解析
服务器·开发语言·后端·golang
senijusene2 小时前
Linux软件编程: 线程属性与线程间通信详解
java·linux·jvm·算法
Stewie121382 小时前
企业高性能web服务器——Nginx
服务器·前端·nginx
shawnyz4 小时前
HAPROXY负载均衡
运维·负载均衡
林开落L7 小时前
解决云服务器内存不足:2 分钟搞定 Ubuntu swap 交换区配置(新手友好版)
运维·服务器·ubuntu·swap交换区
初恋叫萱萱7 小时前
深入解析 Rust + LLM 开发:手把手教你写一个 AI 运维助手
运维·人工智能·rust