如意面板内存优化说明
一句话结论
如意面板空闲时内存占用约 80MB;执行任务(如安装环境)期间会临时升高到 300–500MB;任务结束后自动回收,基本稳定在 110MB 左右。"先升高、后回落"是如意面板的设计行为,不是内存泄漏。
以下数据为实际环境验证结果(任务管理器 / top 的进程内存口径),不同机器因系统、Python 版本、已安装软件不同会略有浮动。
一、实测内存曲线
| 阶段 | 内存占用 | 说明 |
|---|---|---|
| 刚启动 · 无任务 | 约 80MB | 冷启动,仅加载核心模块,大量可选功能模块未加载 |
| 任务执行中(安装环境等) | 300–500MB | 编译工具链、依赖下载解压、子进程叠加 + 文件页缓存 |
| 任务结束后 | 约 110MB | 自动回收后的热稳态,长期运行保持在此水平 |
为什么任务结束后是 110MB 而不是启动时的 80MB?
冷启动时很多模块(SSH 客户端、云厂商适配、IP 归属地库等)尚未加载;运行过任务后,这些模块已经"热身"进内存,加上数据库连接池、各类运行时缓存,热稳态自然略高于冷启动。这 30MB 左右的差值是一次性的,不会随时间继续增长——这正是双层内存回收机制保证的结果(见下文)。
二、为什么任务期间内存会升高
以"安装环境"(如源码编译安装 Nginx/MySQL/Redis)为例,内存峰值由四部分叠加:
- 编译工具链本身:
make/gcc/cc1等编译进程是内存大户,编译 MySQL 这类大型项目时尤其明显 - 下载与解压:pip 下载依赖、解压源码包都会产生临时工作内存
- 子进程叠加:面板主进程 + 安装脚本进程 + 编译进程链同时存活
- 文件页缓存:Linux 会把刚读写过的文件缓存在内存里加速访问,这部分占了大头,但它是可回收内存,内核随时可以拿回来
重要认知
面板主进程自身的稳态内存一直在 110MB 上下,任务期间的"飙升"绝大部分是一次性工作内存 + 页缓存。实测软件安装编译高峰后,文件页缓存由内核自动回收(436MB → 282MB),实现"内存飘高可持续回落"。
三、内存如何自动回落:双层回收机制
任务结束后内存不会一直停留在高水位,如意面板构建了从内核到应用层的多层回收体系:
| 层级 | 机制 | 时机 |
|---|---|---|
| 内核层 | 文件页缓存自动回收 | 内存紧张时内核即时回收 |
| 分配器层 | jemalloc 后台归还堆脏页(mem_optimize.sh 自动安装配置) | 每 60 秒 |
| 应用层 | trim_malloc_task 兜底任务(gc.collect + malloc_trim) | 每 6 小时 |
| 异常防护 | 安装看门狗 install_watchdog_task:安装日志停滞超 30 分钟判定挂起,自动终止安装进程组并释放队列 | 每 2 分钟检查 |
- jemalloc 和
malloc_trim的作用是把 glibc 堆里的空闲页真正归还给操作系统(而不是留在进程内部"自己用不着也不还"),这是防止长期运行 RSS 缓慢漂移的关键 - Windows / 非 glibc 环境自动跳过 malloc_trim,不影响使用
- 安装看门狗防止"管道死锁、脚本卡交互"等未知原因的安装挂起长期占用资源;任务尚在调度队列时自动跳过防误杀
四、常驻内存瘦身:从 188MB 到 116MB
除了"能回落",如意面板更下了大力气把常驻基线打下来:
| 阶段 | 主进程稳态 RSS |
|---|---|
| 优化前 | 约 188MB |
| 第一阶段优化后 | 约 140MB(cgroup 口径 289MB → 115MB) |
| v2.1.6 当前 | 约 116MB(-31% 以上) |
主要手段:
- 按需懒加载:requests/paramiko 及 DNS/CDN 云厂商 provider 全部改为用时才加载(工厂改字符串注册表 +
importlib动态导入),paramiko 的 37 个模块由常驻降为 0 - 去重依赖:chardet 替换为 requests 自带的 charset_normalizer,少加载一整套编码探测库
- IP 库改 mmap:qqwry IP 库由整文件读入堆 + 建索引(实测 +34.1MB 且单例永不释放)改为 mmap 模式,查询性能无感知
- 缓存加上限:IP 归属地缓存新增 2 万条上限,超限自动落盘并裁剪最旧一半,杜绝无界增长
- SQLite 全库调优:12 个分库统一开启 mmap 读路径(
mmap_size=256MB),历史日志类大库查询走文件页缓存,不占堆内存 - 进程池按需创建:修复调度器初始化 ProcessPoolExecutor 导致的常驻
resource_tracker子进程(约 13MB)与任务执行期 fork 内存尖峰,现改为按配置项TASK_USE_PROCESS_POOL按需启用,默认线程池模式 - 管道死锁修复:安装脚本子进程 stderr 无人排空会导致编译链永久冻结、内存长期滞留(实测 redis 安装卡死 11 小时),新增后台守护线程持续排空 stderr,nginx/mysql/pgsql 等 12+ 个安装脚本自动受益
五、给小内存机器的保护措施
1. 面板内存限制(v2.1.6,仅 Linux)
在 面板设置 页可自行调节面板的 MemoryHigh 软上限:
- 推荐档位 256 / 500 / 1024 / 2048MB(按当前用量 3 倍自动首推),或自定义 128MB–65536MB,也可一键取消限制
- 超限后仅回收页缓存并节流内存分配,面板变慢但不会被强制终止,任务依然能跑完
- 配置写入
/ruyi/data/memlimit.ry作为单一事实来源,由内存优化自愈脚本mem_optimize.sh自动收敛为 systemd drop-in,设置立即生效、重启升级后持久保留 - 支持 systemd + cgroup v2 环境(Debian 11+、Ubuntu 22.04+、RHEL/Rocky/Alma 9+、Fedora 31+ 等);Windows、CentOS 7/8(cgroup v1)环境该功能自动隐藏
2. 内存压力趋势图(v2.1.6)
内置 ECharts 图表:进程 RSS 与 cgroup 实际用量双曲线 + 当前限制值虚线,支持 3/6/24 小时区间切换,同时显示本次运行限流触发次数与 PSI 内存压力指标,内存状态一目了然。
3. 内存采样任务(可选)
panel_mem_collect 采样任务默认关闭,可在面板设置页按需开启(采样间隔 30–3600 秒可调),数据写入监控分库并自动保留最近 3 天,方便回溯内存变化。
六、常见问题
Q:任务执行期间内存涨到 400MB+,正常吗?
正常。编译安装类任务的工作内存 + 文件页缓存本就很大,任务结束后会自动回落,可开启内存采样任务或在内存趋势图中观察回落曲线。
Q:内存会随着运行时间一直缓慢上涨吗?
不会。jemalloc(每 60 秒)+ malloc_trim 兜底任务(每 6 小时)构成双层回收,IP 缓存等所有运行时缓存均有容量上限,长期运行内存稳定在 110MB 左右。
Q:1GB 内存的小机器能跑吗?
可以。空闲约 80MB、稳态约 110MB 的基线专为小内存场景优化,配合"面板内存限制"功能可进一步约束峰值行为(超限节流不变慢到不可用,也不会被 OOM 杀掉)。
Q:怎么验证我机器上的内存表现?
Linux 下可用 systemctl status ruyi 或 top 观察进程 RSS;也可以在面板设置页开启内存采样任务,通过内存压力趋势图查看历史曲线。
更多版本细节见更新日志。
