MySQL长时间运行后内存碎片通常无需重启解决,实际多为Buffer Pool中old页未及时驱逐或冷启动配置不当所致;真有内存泄漏才需排查而非简单重启。

MySQL长时间运行后内存碎片真的需要靠重启解决?
不推荐把定时重启当作常规手段。MySQL的内存管理(尤其是InnoDB Buffer Pool)本身具备自适应回收和重用机制,所谓“内存碎片”多数是误判——实际是Buffer Pool中大量页被标记为old但未被驱逐,或innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup没配好导致冷启动慢,被当成“卡顿”。真有内存泄漏(如插件bug、严重版本缺陷),重启只是掩盖问题。
哪些现象才说明该查内存而非直接重启?
先确认是不是内存相关问题,而不是慢查询、锁等待或磁盘I/O瓶颈:
-
SHOW ENGINE INNODB STATUS\G中BUFFER POOL AND MEMORY部分显示Free buffers持续为 0,且Database pages接近Buffer pool size,但Pages made young极低( - 系统级监控发现
mysqld进程 RSS 持续上涨且不回落(排除缓存文件映射干扰),配合pstack或gdb抓栈发现大量线程卡在内存分配路径(如malloc、os_mem_alloc_large) - 启用
performance_schema后查memory_summary_global_by_event_name,发现memory/innodb/buf_buf_pool或memory/sql/THD::main_mem_root占比畸高且随时间单边增长
如果真要重启,必须绕开的三个坑
硬杀进程或简单 systemctl restart mysqld 在生产环境极易引发数据不一致或主从断裂:
- 必须等
SHOW PROCESSLIST中所有Command为Query的连接完成(尤其长事务),否则innodb_fast_shutdown=1(默认)会跳过完整刷脏,下次启动需更久恢复 - 主库重启前务必确认
SHOW MASTER STATUS记录的File和Position,从库执行STOP SLAVE; CHANGE MASTER TO ...后再启,避免复制跳过事务 - 若启用了
innodb_undo_log_truncate=ON,重启前检查INFORMATION_SCHEMA.INNODB_METRICS中undo_truncations是否活跃,正在截断时重启可能卡在初始化阶段
比重启更稳的日常内存健康维护方式
重点不是清内存,而是让内存用得更“干净”:
- 调大
innodb_old_blocks_time(默认0 → 建议1000),减少热点页被误踢出old子链,降低无效重载 - 每天低峰期手动触发一次
SET GLOBAL innodb_buffer_pool_dump_now = ON,确保热数据快照及时落盘,下次启动加载更快 - 对长期只读库,可设
innodb_buffer_pool_invalidate_threshold_pct=5(8.0.22+),避免冷数据长期占位 - 禁用非必要插件(如
audit_log、connection_control),它们常在THD内存池中累积小块未释放内存
真正难处理的是那些不释放的THD级内存——比如某个存储过程反复PREPARE/EXECUTE但没DEALLOCATE PREPARE,这种问题重启只能临时缓解,必须代码层修复。


















