MySQL重启后内存快速回升是因innodb_buffer_pool_load_at_startup默认开启,自动加载ib_buffer_pool中上次dump的热页;该行为非内存泄漏,而是预热机制,但若热数据远小于buffer pool容量则造成浪费。

MySQL重启后内存占用快速回升到峰值,不是配置没生效,而是它在“认真预热”——尤其是 innodb_buffer_pool_load_at_startup 默认开启时,会主动把上次关机前 dump 的热页(ib_buffer_pool 文件)加载进内存。
为什么 buffer pool 一启动就飙高?
MySQL 8.0+ 默认启用 innodb_buffer_pool_dump_at_shutdown 和 innodb_buffer_pool_load_at_startup。只要上一次是正常关闭,InnoDB 就会在启动后由后台线程悄悄加载 ib_buffer_pool 中记录的页帧,这个过程不阻塞服务,但 RSS 内存几秒内就能涨上去。
- 检查是否启用:
SHOW VARIABLES LIKE 'innodb_buffer_pool_load_at_startup';—— 若为ON,就是它在“干活” -
ib_buffer_pool文件默认在数据目录下,用ls -lh ib_buffer_pool看大小:如果文件有几百MB甚至GB级,说明 dump 范围太宽,不一定是当前热数据 - 这个行为不是泄漏,也不代表负载高;但若实例重启频繁、或热数据集远小于 buffer pool 总容量(比如 24G pool 只存了 3G 常用数据),预热反而浪费内存和 I/O
为什么 performance_schema 查不到这部分内存?
performance_schema.memory_summary_global_by_event_name 统计的是走 PFS 分配路径的内存,而 buffer pool 的页帧本身(即实际缓存的数据页)不在其监控范围内——它只记元数据(如 buf_buf_pool 对象),不记页内容所占物理内存。
- 执行
SELECT SUM(current_number_of_bytes_used) FROM performance_schema.memory_summary_global_by_event_name得到的总和,通常只有几百MB,远低于ps aux显示的 VmRSS(比如 18G) - 这种“查不到但真实存在”的内存,90%以上属于 buffer pool 页帧、复制线程缓存(如
relay_log_buffer)、或 glibc 分配器未归还 OS 的碎片空间 - 别指望靠 PFS 找出“谁吃掉了 15G”,它根本看不到那块主阵地
怎么让重启后内存不猛涨?
停掉预热是最直接的办法,但得配合 dump 策略调优,否则下次关机又 dump 全量,问题照旧。
- 临时禁用:
SET GLOBAL innodb_buffer_pool_load_at_startup = OFF;(立即生效,但重启后恢复默认) - 持久化禁用:在
my.cnf的[mysqld]段落加一行innodb_buffer_pool_load_at_startup = OFF - 同时收紧 dump 范围:设
innodb_buffer_pool_dump_pct = 10(只 dump 最热 10% 的页,而非默认 25%),减少下次启动要加载的数据量 - 注意:
innodb_buffer_pool_dump_at_shutdown可以保留为ON,它本身不耗内存,只是写磁盘;真正影响启动内存的是 load 行为
buffer pool 预热逻辑本身没问题,问题出在“默认全量 dump + 全量 load”和实际业务热数据分布不匹配。一旦热数据集稳定且远小于 buffer pool 容量,就该关掉自动 load,并用 dump_pct 控制 dump 粒度——否则每次重启都在重复搬运一堆冷数据进内存。


















