MySQL 8.0升级后内存异常飙高主因是innodb_buffer_pool_size自动推导突变叠加performance_schema全量启用;需显式配置chunk_size与instances并关闭非必要P_S consumer。

MySQL 8.0 升级后内存异常飙高,90%以上情况不是 bug,而是两个默认行为突变叠加导致的:一是 innodb_buffer_pool_size 从固定小值(5.7 默认 128MB)变成按物理内存自动推算(如 64GB 机器默认分 48GB),二是 performance_schema 全量启用,光 events_statements_history_long 就预分配 128MB+ 内存——两者加起来轻松多占 500MB–数 GB RSS。
为什么 SHOW VARIABLES 显示的 innodb_buffer_pool_size 和实际 RSS 差一大截
你配置的 innodb_buffer_pool_size 只是“目标值”,InnoDB 实际分配时必须满足:innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances × 整数倍。MySQL 8.0.22+ 会自动推导 innodb_buffer_pool_chunk_size(比如 64GB 机器算出 256MB),若你没显式设死,就极易出现向上对齐现象。
常见表现:
-
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'返回 40GB,但SHOW ENGINE INNODB STATUS\G里 “Buffer pool size” 显示 5242880 × 16KB ≈ 80GB - 启动日志出现 warning:“Buffer pool size rounded up to …”
-
SELECT @@innodb_buffer_pool_chunk_size, @@innodb_buffer_pool_instances, @@innodb_buffer_pool_size结果无法整除
解决方法:在 /etc/my.cnf 的 [mysqld] 段显式写死:
innodb_buffer_pool_chunk_size = 128M innodb_buffer_pool_instances = 4
确保 innodb_buffer_pool_size 能被 128 * 1024 * 1024 * 4 整除(例如设为 2G、4G、8G)。删掉旧的 ib_logfile0 和 ib_logfile1,否则可能启动失败。
为什么 performance_schema 一开就多占 300–500MB
MySQL 8.0 默认全量启用所有 instruments 和 consumers,其中 events_statements_history_long 和 events_transactions_history_long 这类长历史表,单个默认预分配 128MB+ 内存,且是启动即占——不查也吃。
验证方式:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
SELECT * FROM performance_schema.memory_summary_global_by_event_name WHERE event_name LIKE 'memory/performance_schema/%' ORDER BY SUM_ALLOCATED DESC LIMIT 10;
实操建议:
- 关掉非调试用 consumer:
UPDATE performance_schema.setup_consumers SET ENABLED = 'NO' WHERE NAME IN ('events_statements_history_long', 'events_transactions_history_long'); - 限制大小(写入 my.cnf):
performance_schema_events_statements_history_long_size = 10000(默认 20000) - 禁用非核心 instruments(运行时生效):
UPDATE performance_schema.setup_instruments SET ENABLED = 'NO' WHERE NAME LIKE 'statement/sql/%' AND NAME NOT IN ('statement/sql/select','statement/sql/insert','statement/sql/update','statement/sql/delete');
为什么改了 my.cnf 却不生效
很多用户在宝塔里改了 /www/server/mysql/my.cnf,但 MySQL 8.0 启动时只认固定路径:/etc/my.cnf → /etc/mysql/my.cnf → /usr/etc/my.cnf → ~/.my.cnf。/www/server/mysql/my.cnf 不在默认列表里,除非显式加 --defaults-file 参数。
确认实际加载的配置:
ps aux | grep mysqld | grep -o '\-\-defaults-file=[^ ]*'
若无输出,说明走的是默认路径。最稳妥做法:
- 删掉或重命名
/etc/my.cnf(避免它覆盖你的配置) - 确保
/www/server/mysql/my.cnf顶部有[mysqld]段落 - 把所有关键参数(
innodb_buffer_pool_size、performance_schema相关项等)都放进去
真正容易被忽略的点是:buffer pool 预热和 P_S 内存都是“启动即占”,不是运行中缓慢增长;所以重启后几秒内 RSS 突增是正常行为,别误判为泄漏。调参后一定要看 SHOW ENGINE INNODB STATUS\G 和 performance_schema.memory_summary_global_by_event_name,而不是只信 SHOW VARIABLES。










