From 7806524279ed35627ff52c8c4b7cadf842f55f6c Mon Sep 17 00:00:00 2001 From: RRRosmontis Date: Sat, 19 Sep 2026 23:58:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=AF=8F=E6=97=A5?= =?UTF-8?q?=E5=86=85=E5=AD=98=E5=9B=9E=E6=94=B6=E4=B8=8E=20malloc=20arena?= =?UTF-8?q?=20=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 流媒体会话会在 glibc malloc arena 中留下大量不归还操作系统的冷匿名内存,实测单个 服务可累积到 2.5 GB 并占满整个 swap 文件(33 个 64/128 MB 匿名段,空闲时不增长, 随会话单调抬升)。本次从根因与兜底两侧处理: - systemd/maa-online-server.service: 设置 MALLOC_ARENA_MAX=2,把线程 arena 数量 从 8xCPU 压到 2,抑制 arena 膨胀 - systemd/maa-daily.service: 单元结束时经 ExecStopPost 重启 API 服务,回收当次会话残留 - systemd/maa-online-recycle.service, maa-online-recycle.timer: 新增每日 03:59(游戏 每日刷新前)独立回收定时器,错开更新与日常任务窗口,Persistent=false 避免补跑撞车 - bin/maa-online-can-recycle: 回收守卫,检测日常任务(systemd 单元或手工运行)是否 进行中,是则跳过回收,避免重启打断任务 - bin/maa-online-install-systemd: 安装并启用新增的回收单元 - README.md, user_config/README.md: 补充内存回收机制与定时器说明 --- README.md | 10 ++++++++-- bin/maa-online-can-recycle | 24 ++++++++++++++++++++++++ bin/maa-online-install-systemd | 10 +++++----- systemd/maa-daily.service | 8 ++++++-- systemd/maa-online-recycle.service | 12 ++++++++++++ systemd/maa-online-recycle.timer | 16 ++++++++++++++++ systemd/maa-online-server.service | 6 ++++++ user_config/README.md | 8 +++++++- 8 files changed, 84 insertions(+), 10 deletions(-) create mode 100755 bin/maa-online-can-recycle create mode 100644 systemd/maa-online-recycle.service create mode 100644 systemd/maa-online-recycle.timer diff --git a/README.md b/README.md index 0f88c75..20713a5 100644 --- a/README.md +++ b/README.md @@ -146,14 +146,20 @@ sudo bin/maa-online-install-systemd | 单元 | 作用 | |---|---| -| `maa-online-server.service` | 云游戏 API 常驻服务(`Restart=always`,启动前清除代理环境变量) | +| `maa-online-server.service` | 云游戏 API 常驻服务(`Restart=always`,启动前清除代理环境变量,限制 malloc arena 数量) | | `maa-daily.timer` | 每天 04:00 起随机 0–2 小时触发日常任务 | +| `maa-online-recycle.timer` | 每天 03:59(游戏每日刷新前)重启 API 服务,回收内存 | | `maa-update.timer` | 每周日 03:20 起随机 30 分钟执行更新 | 日常任务由 `bin/maa-online-daily-run` 驱动:等待 API 就绪 → 启动云游戏 → 在停滞看门狗下执行 `config/tasks/daily.toml` → 失败则释放云会话并重试。定时器使用 `Persistent=true`,机器重启 错过触发时间后会自动补跑;同一单元不会并发执行。 +**内存回收**:一次流媒体会话会在 glibc 的 malloc arena 里留下大量不归还操作系统的冷匿名内存 +(实测单个服务可累积到 2.5 GB 并填满 swap),因此有两层回收:`maa-daily.service` 在结束时 +重启 API 服务(`ExecStopPost`),`maa-online-recycle.timer` 每天再独立回收一次。回收服务带 +`ExecCondition=bin/maa-online-can-recycle` 守卫,日常任务运行期间会被自动跳过,不会打断任务。 + 重试采用**断点续跑**:`bin/maa-resume-tasks.py` 读取前几次尝试的日志,跳过已出现 `<任务类型> Completed` 的任务,只运行剩余任务;若全部完成则直接判定成功,不再开启新会话。 `StartUp` 永不跳过,因为每次 `/start` 都是全新的云实例。详见 @@ -162,7 +168,7 @@ sudo bin/maa-online-install-systemd 查看运行情况: ```bash -systemctl list-timers maa-daily.timer maa-update.timer +systemctl list-timers maa-daily.timer maa-update.timer maa-online-recycle.timer journalctl -u maa-daily.service -n 50 journalctl -u maa-online-server.service -n 50 ``` diff --git a/bin/maa-online-can-recycle b/bin/maa-online-can-recycle new file mode 100755 index 0000000..c5cc48a --- /dev/null +++ b/bin/maa-online-can-recycle @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Guard for maa-online-recycle.service. +# +# Exit 0 when it is safe to restart the cloud game API server, exit 1 when a +# daily run is in progress. Restarting the server underneath a running task +# breaks that attempt, and the recycle timer fires right next to the daily +# window, so the recycle must never race with it. +set -uo pipefail + +state=$(systemctl show -p ActiveState --value maa-daily.service 2>/dev/null || echo unknown) +case "$state" in + active|activating|reloading|deactivating) + echo "maa-daily.service is '$state'; skipping recycle" >&2 + exit 1 + ;; +esac + +# Cover a run started by hand (bin/maa-online-daily-run outside systemd). +if pgrep -x maa >/dev/null 2>&1; then + echo "a maa task is running; skipping recycle" >&2 + exit 1 +fi + +exit 0 diff --git a/bin/maa-online-install-systemd b/bin/maa-online-install-systemd index 7ceef4f..03f9665 100755 --- a/bin/maa-online-install-systemd +++ b/bin/maa-online-install-systemd @@ -7,7 +7,7 @@ set -euo pipefail ROOT="${MAA_ONLINE_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" SRC="$ROOT/systemd" DST="${MAA_ONLINE_SYSTEMD_DIR:-/etc/systemd/system}" -UNITS=(maa-online-server.service maa-daily.service maa-daily.timer maa-update.service maa-update.timer) +UNITS=(maa-online-server.service maa-daily.service maa-daily.timer maa-update.service maa-update.timer maa-online-recycle.service maa-online-recycle.timer) if [ "$(id -u)" != "0" ]; then echo "error: must run as root (writes to $DST)" >&2 @@ -25,15 +25,15 @@ done systemctl daemon-reload systemctl enable --now maa-online-server.service -systemctl enable maa-daily.timer maa-update.timer -systemctl start maa-daily.timer maa-update.timer +systemctl enable maa-daily.timer maa-update.timer maa-online-recycle.timer +systemctl start maa-daily.timer maa-update.timer maa-online-recycle.timer echo -systemctl --no-pager list-timers maa-daily.timer maa-update.timer +systemctl --no-pager list-timers maa-daily.timer maa-update.timer maa-online-recycle.timer cat <