MySQL 8.0升级后内存“暴涨”主因是innodb_buffer_pool_size默认行为突变(8.0+按物理内存自动计算,5.7及以前用保守固定值)叠加performance_schema全开占用300–500MB;需显式配置buffer pool大小与chunk_size、关闭非必要P_S consumer并协同调优max_connections等参数。

MySQL 8.0 升级后内存“暴涨”,90%以上情况不是 bug,而是 innodb_buffer_pool_size 默认行为突变 + performance_schema 全开导致的——调这两个,基本能压下 80% 的异常 RSS 增长。
为什么 SHOW VARIABLES 显示的 innodb_buffer_pool_size 和实际 RSS 差一大截
MySQL 8.0.22+ 启用自动推导 innodb_buffer_pool_chunk_size,若你没显式设置它,MySQL 会按物理内存动态算 chunk 大小(比如 64GB 机器算出 256MB),再乘以 innodb_buffer_pool_instances(默认 8),最终分配内存 = chunk × instances × 实际 chunk 数量。而你配置的 innodb_buffer_pool_size 只是“目标值”,InnoDB 会向上对齐到最近合法倍数。
常见表现:
-
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'返回 42949672960(40GB),但SHOW ENGINE INNODB STATUS\G里 “Buffer pool size” 显示 5242880(即 5242880 × 16KB ≈ 80GB) - 手动计算:
SELECT @@innodb_buffer_pool_chunk_size, @@innodb_buffer_pool_instances, @@innodb_buffer_pool_size;,发现innodb_buffer_pool_size不能被chunk_size × instances整除 - 启动日志出现 warning:“Buffer pool size rounded up to …”
解决方法:
- 在
/etc/my.cnf的[mysqld]段显式写死:innodb_buffer_pool_chunk_size = 128M(推荐值,必须是 1M 整数倍) - 同步调整
innodb_buffer_pool_instances,确保innodb_buffer_pool_size / (128 * 1024 * 1024 * innodb_buffer_pool_instances)是整数(例如设为 2G 时,instances 设 2 或 4 或 8) - 删掉旧的
ib_logfile0和ib_logfile1(路径通常为/www/server/data/或/var/lib/mysql/),否则启动报错
为什么 performance_schema 一开就多占 300–500MB 内存
MySQL 8.0 默认全量启用 performance_schema 的 instruments 和 consumers,其中 events_statements_history_long 和 events_transactions_history_long 这类长历史表,单个默认预分配 128MB+,且是启动即占,不查也吃内存。
验证方式:
- 运行
SELECT * FROM performance_schema.memory_summary_global_by_event_name WHERE event_name LIKE 'memory/performance_schema/%' ORDER BY SUM_ALLOCATED DESC LIMIT 10; - 如果
memory/performance_schema/events_statements_history_long排前三,基本就是它
实操降内存:
- 关掉非调试 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');
为什么改了配置重启后还是 OOM,甚至 dmesg 出现 kill process mysqld
两个高频陷阱:一是配置文件根本没被 MySQL 加载;二是 buffer pool 预热机制在启动时瞬间拉高内存峰值。
检查是否读对配置:
- MySQL 8.0 只认固定路径:
/etc/my.cnf→/etc/mysql/my.cnf→/usr/etc/my.cnf→~/.my.cnf;宝塔用户常改的/www/server/mysql/my.cnf不在默认列表里 - 校验语法:
mysqld --defaults-file=/www/server/mysql/my.cnf --verbose --help 2>/dev/null | head -5,不报错才说明路径和格式 OK
buffer pool 预热问题:
- 确认是否启用:
SHOW VARIABLES LIKE 'innodb_buffer_pool_load_at_startup';(默认 ON) - 临时关闭:
SET GLOBAL innodb_buffer_pool_load_at_startup = OFF;,并写入 my.cnf 持久化 - 若 buffer pool > 4G,建议同时调小 dump 范围:
innodb_buffer_pool_dump_pct = 10(默认 25)
真正容易被忽略的是:innodb_buffer_pool_size 设置值本身不是孤立参数——它必须和 max_connections、sort_buffer_size 等 per-connection 参数协同控制。单独把 buffer pool 从 4G 降到 2G,但 max_connections 还是 1000,每个连接配 2MB 临时表缓冲,照样爆内存。


















