Files
DeltaZern/zernmc-config/README.md
T
SashegDev 42f48fea43
Build Delta / Build paperclip jar (push) Successful in 7m3s
perf(config): document and justify the heap-shrink flags
Добавлен -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10 в start.sh на проде
и зафиксирован в README с замерами, потому что флаги JVM не переносятся
копированием конфигов — при переезде они теряются молча.

Замер, мир 18 МБ, 0 игроков, 100 с простоя:

              коммит   живые   RSS
  без флагов   630 МБ  278 МБ  0.99 ГБ
  с флагами    389 МБ  274 МБ  0.69 ГБ

Минус 300 МБ RSS без единого ручного GC.

Причина была не в отсутствии Full GC: jcmd GC.run отрабатывает, живые падают
289 -> 248 МБ, но коммит остаётся на 725 МБ. G1 сжимает кучу только когда
свободно выше MaxHeapFreeRatio, а он по умолчанию 70. При 630 МБ коммита
свободно было 56% — ниже порога, и 350 МБ держались вечно.

Паузы Mixed (то, что ест кадр в рантайме) не ухудшились: median 11.0 -> 9.8,
p95 28.3 -> 28.1, max 38.1 -> 28.7 мс. Concurrent-циклов стало больше
(11 -> 18), общий p95 по всем паузам в одном прогоне вырос 126 -> 270 мс —
это замер без игроков, под нагрузкой флаг ещё предстоит перемерить.

DisableExplicitGC оставлен намеренно: он делает System.gc() no-op, и именно
поэтому освобождение сделано флагом, а не вызовом GC. README теперь
описывает профиль как 15-25 игроков с пиком 34, а не 30-40.
2026-10-04 13:55:14 +00:00

122 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ZernMC configs
Тюнинг под профиль: **4 vCPU / 8 GB RAM, 15–25 игроков постоянно, пик 34**,
боевой сервер с плагином, который спавнит много `Display`/`Marker` сущностей и
частиц (BlackKnife как референс).
Все файлы **парциальные** — Paper/Spigot дополняет недостающие ключи
дефолтами, поэтому их можно копировать поверх существующих конфигов.
## Куда класть
| Файл | Путь на сервере |
|---|---|
| `spigot.yml` | `<сервер>/spigot.yml` |
| `paper-world.yml` | `<сервер>/<мир>/paper-world.yml` — **у каждого мира свой** |
| `paper-global.yml` | `<сервер>/config/paper-global.yml` |
| `server.properties.patch` | ключи из него в `<сервер>/server.properties` |
## Что где меняем и зачем
### `spigot.yml`
- `view-distance 8 / simulation-distance 5` — на 4 ядрах это самый
ощутимый рычаг: симуляция шириной 10 стоит в разы дороже 5.
- `entity-tracking-range.display 128 → 48` — **главный фикс**. Display,
ItemDisplay, TextDisplay, Marker шлются игрокам пачками; при спаме
боеспособностей 128 это десятки пакетов на тик.
- `misc 96 → 48`, `other 64 → 32`, `animals/monsters 96 → 64`,
`players 128 → 96` — то же, но по остальным типам.
- `entity-activation-range` — сужаем радиусы, в которых сущности вообще
тикают; `tick-inactive-villagers: false` — самый частый выигрыш.
- `ticks-per.hopper-check 1 → 8` — хопперы по умолчанию проверяются
каждый тик, 8 экономит заметно и не ломает фермы.
- `merge-radius.item 0.5 → 2.5` — меньше сущностей-дропа на земле.
- `item-despawn-rate 6000 → 3000`, `arrow-despawn-rate 1200 → 300`.
- `mob-spawn-range 8 → 6`, `max-tnt-per-tick 100 → 30`.
### `paper-world.yml`
- `misc.redstone-implementation: ALTERNATE_CURRENT` — быстрее
распространение редстоуна. **Ломает 0-tick и двери-контры**, предупредить
игроков перед включением.
- `tick-rates` — рост травы, обновление контейнеров, спавнеры в 3 тика.
- `collisions.max-entity-collisions 8 → 5`.
- `environment.disable-thunder`, `optimize-explosions`,
`max-block-ticks`/`max-fluid-ticks` пополам.
- `hopper.disable-move-event: true` — **ломает плагины, слушающие
`InventoryMoveItemEvent`** (авто-сортировки, economy-логики).
- `entities.spawning.spawn-limits` — потолок мобов на чанк.
### `paper-global.yml`
- **`chunk-system.worker-threads: 2`** — самый недооценённый рычаг. `auto`
(`-1`) на 4 ядрах даёт **1 воркер**, и генерация чанков идёт
последовательно: Moonrise делит `availableProcessors` пополам, а на
результате 2 опускается до 1, оставляя место главному треду.
Замерено: холодный старт **38.5 → 24.9 с**, тёплый **16.4 → 12.2 с**.
Значение 3 — только с профилем, главному треду на 4 ядрах нужно дышать.
- `chunk-system.io-threads: 2`, `gen-parallelism: true`.
- `chunk-loading.advanced.player-max-concurrent-chunk-loads/generates` —
защита от флуда генерацией при скоростном облёте. **При ускорении
генерации этот потолок надо поднимать**, иначе движер быстрее, а
ограничитель остался прежним.
## Что НЕ трогаем
- Moonrise (чанковая система) — уже многопоточный, отдельный патч не нужен.
- `wake-up-inactive.*` — баланс, не перф.
## JVM-флаги кучи (живут в `start.sh`, не в конфигах)
Эти флаги **не переносятся копированием конфигов** — они в скрипте запуска.
Потеряются при переезде, поэтому дублируются здесь.
### `-XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10`
Замер на сервере с миром 18 МБ, 0 игроков, после 100 с простоя:
| | коммит | живые | RSS |
|---|---|---|---|
| без флагов | 630 МБ | 278 МБ | **0.99 ГБ** |
| с флагами | 389 МБ | 274 МБ | **0.69 ГБ** |
Минус 300 МБ RSS на пустом сервере, без единого вызова GC вручную.
Почему работает. `G1PeriodicGC` гоняет Mixed/Remark каждые 15 с, но кучу
почти **никогда не сжимает**: G1 сжимает только когда доля свободной памяти
выше `MaxHeapFreeRatio`, а он по умолчанию **70**. При 630 МБ коммита и 278 МБ
живых свободно было 56% — ниже порога, поэтому 350 МБ коммита держались
вечно и в RSS, и в физической памяти.
Отдельно проверено, что принудительный Full GC сам по себе **не помогает**:
`jcmd GC.run` отработал, живые упали 289 → 248 МБ, а коммит остался на
725 МБ. То есть дело не в отсутствии Full GC, а именно в пороге.
Паузы при этом не ухудшились — то, что реально ест кадр в рантайме:
| Pause Young (Mixed) | без флагов | с флагами |
|---|---|---|
| median | 11.0 мс | 9.8 мс |
| p95 | 28.3 мс | 28.1 мс |
| max | 38.1 мс | 28.7 мс |
Оговорка: concurrent-циклов стало больше (11 → 18), потому что куча меньше и
G1 переполняет её чаще. Каждый такой цикл начинается с STW-паузы, и общий
p95 по всем паузам в одном прогоне вырос (126 → 270 мс). Это замер на сервере
без игроков, один прогон — **под нагрузкой это надо перемерить**, прежде чем
считать флаг безопасным.
### `-XX:+DisableExplicitGC`
Оставлен намеренно: `System.gc()` отключён, чтобы ни плагин, ни сторонний код
не могли вызвать stop-the-world сборку в неподходящий момент. Именно поэтому
освобождение кучи сделано флагом, а не вызовом GC.
### Что будет, когда мир вырастет до 2–4 ГБ
Флаг этого не ломает. Он разрешает сжимать кучу, когда свободно больше 30%,
и не мешает расти: при `-Xmx4G` G1 расширится сам, как только живых данных
станет больше. Экономия в 300 МБ в основном на простое и при малом мире.
## Порядок применения
1. Остановить сервер.
2. Скопировать файлы.
3. `paper-world.yml` положить в **каждый** мир: `world/`, `world_nether/`, `world_the_end/`.
4. Флаги кучи из раздела выше — в `start.sh`, вручную.
5. Старт → в логе не должно быть `Error occurred while loading` по этим файлам.
6. Проверить: `/paper entity` (tracking ranges), `spark` для TPS/MSPT.