MySQL 8.0 极少发生C堆内存泄漏,“泄漏感”90%源于配置失当或连接堆积;需启用memory instruments与consumers,通过memory_summary_global_by_event_name等视图定位内存大户,并结合OS层与SQL行为综合排查。

MySQL 8.0 本身极少发生传统 C 堆内存泄漏,所谓“泄漏感”90% 是配置失当、连接堆积或查询滥用导致的 RSS 持续上涨——Performance Schema 是唯一能告诉你“内存到底花在哪”的实时仪表盘,但必须手动开全才能用。
performance_schema 内存监控没真正启用
很多人执行 SHOW VARIABLES LIKE 'performance_schema' 看到 ON 就以为万事大吉,其实只是开关开了,memory/% instruments 和 consumers 很可能还关着。
- 必须显式启用内存采集:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%'; - 同时打开全局和线程级消费者:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME IN ('global_instrumentation', 'thread_instrumentation'); - 验证是否就绪:
SHOW ENGINE PERFORMANCE_SCHEMA STATUS,只看最后一行是不是OK;不是就得重启 mysqld 或检查启动参数是否含--performance-schema=ON
查 memory_summary_global_by_event_name 定位内存大户
这是第一把刀。别只盯 CURRENT_NUMBER_OF_BYTES_USED,HIGH_NUMBER_OF_BYTES_USED(峰值)更关键——持续上涨不回落才是泄漏信号。
- 重点关注三类事件:
memory/innodb/mem0mem(InnoDB 内部结构,非 buffer pool)、memory/temptable/allocator(内存临时表)、memory/sql/thd(每个连接的线程上下文) -
memory/innodb/mem0mem长期高位?结合SHOW ENGINE INNODB STATUS查SEMAPHORES和TRANSACTIONS区块,大概率是未提交事务或锁等待堆积,导致字典缓存/锁结构膨胀 -
memory/temptable/*异常高?立刻检查tmp_table_size和max_heap_table_size——设成 2G 不是“更稳”,是鼓励引擎把大结果全塞进内存,反而诱发 OOM - 看到
memory/sql/Query_cache?赶紧关掉:SET GLOBAL query_cache_type = 0,MySQL 8.0 已废弃,留着只会碎片化内存
按线程查 memory_summary_by_thread_by_event_name 找肇事连接
很多“泄漏”其实是应用端连接池没配好,几百个空闲连接堆在那,每个都带着 sort_buffer_size、read_buffer_size 等线程级 buffer,RSS 就无声无息涨上去了。
- 执行:
SELECT thread_id, user, event_name, sys.format_bytes(CURRENT_NUMBER_OF_BYTES_USED) AS memory_used FROM performance_schema.memory_summary_by_thread_by_event_name WHERE CURRENT_NUMBER_OF_BYTES_USED > 1024*1024 ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 10; - 如果发现某个
user(比如reporting_app@10.0.1.%)长期持有大量memory/sql/thd或memory/temptable/allocator,基本可锁定是该应用某类查询有问题 - 配合
SHOW PROCESSLIST看状态:若线程长期卡在Sending data、Copying to tmp table或Sorting result,就是它了
别漏掉 OS 层和配置层的隐性泄漏源
Performance Schema 只告诉你“谁吃了”,但吃得多不一定错——得看是不是被逼的。真正压垮 MySQL 的,往往是配置和 OS 层的组合拳。
-
innodb_buffer_pool_size设太高(比如超物理内存 70%),再叠加大量连接的线程缓冲,OOM Killer 就等着动手 -
sort_buffer_size、join_buffer_size等线程级参数,单个不打眼,但乘以max_connections就很吓人;建议单值不超过 2M~4M - Linux THP(Transparent Huge Pages)开启时,InnoDB 内存分配易碎片化,表现为 RSS 上升快、释放慢;生产环境建议禁用:
echo never > /sys/kernel/mm/transparent_hugepage/enabled - 用
pmap -x $(pgrep mysqld)对比 RSS 和实际分配量,若 RSS 远大于 Performance Schema 统计总和,大概率是 malloc 层碎片或 THP 问题
最常被忽略的一点:memory/innodb/mem0mem 和 memory/temptable/allocator 都不会自己暴涨——它们背后一定有对应的慢查询、长事务或错误配置在驱动。Performance Schema 给你的是线索,不是结论;查到高内存事件后,必须立刻反向追踪 SQL 和会话行为,否则永远在治标。











