真实可用内存看 linux 的 free -h 中 available 列(

先看系统真实可用内存,别信任务管理器的“已使用”
Windows 任务管理器或 Linux top 显示 mysqld 占了 4GB+,不等于它真在“吃”这么多——Linux 的 page cache 和 Windows 的系统缓存会让 RSS 数值虚高。关键看两点:
• Linux 下执行 free -h,盯紧 available 列,低于总内存 10% 就危险;
• Windows 下打开“性能监视器”,添加计数器 MySQL:Innodb_buffer_pool_pages_free,如果长期接近 0,说明缓冲池撑满且系统没余量喂它;
• 执行 dmesg | grep -i oom(Linux)或检查 Windows 事件查看器中是否有 System Out of Memory 记录,有就是已经触发杀进程机制。
查 innodb_buffer_pool_size 是不是设得太大
这是 MySQL 8.0 内存爆表的头号原因,尤其在 Windows 下:它启动就锁定整块内存,而 Windows 缓存回收慢、系统预留余量少,极易抢光资源。
• 先确认当前值:mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';",结果单位是字节,除以 1024*1024*1024 得 GB;
• 对比服务器总内存:专用库不超过 70%,混部服务(如和 Nginx、Redis 同机)必须压到 40% 以内;
• 注意硬约束:改小该值时,必须是 innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances 的整数倍(默认 chunk=128M, instances=8 → 最小合法值=1G);
• 改完必须删掉旧日志文件:ib_logfile0 和 ib_logfile1(路径通常为 C:\ProgramData\MySQL\MySQL Server 8.0\Data\),否则 MySQL 启动卡死报错 InnoDB: Error: log file ib_logfile0 is of different size。
用 performance_schema 定位真实内存消费者
MySQL 8.0 默认全开 performance_schema,但 events_statements_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 5;;
• 关非必要 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);
• 确认配置生效路径:MySQL 8.0 只认固定顺序:/etc/my.cnf → /etc/mysql/my.cnf → ~/.my.cnf,宝塔改的 /www/server/mysql/my.cnf 默认不读,要用 ps aux | grep mysqld | grep --defaults-file 验证是否加载成功。
抓活跃连接和低效 SQL,别只调参数
很多内存暴涨不是配置问题,而是运行时行为触发:
• 执行 SHOW FULL PROCESSLIST;,重点过滤状态为 Copying to tmp table、Sorting result、Sending data 且 Time 值大于 60 秒的线程;
• 这类 SQL 往往因缺失索引导致大排序/大分组,会突破 tmp_table_size 和 max_heap_table_size 限制,转磁盘前先吃光内存;
• 检查用户级内存消耗:SELECT user, host, ROUND(SUM(current_number_of_bytes_used)/1024/1024, 2) AS MB FROM performance_schema.memory_summary_by_account_by_event_name GROUP BY user, host ORDER BY MB DESC LIMIT 5;,若某业务账号持续占 50MB+,大概率存在未关闭游标、长事务或批量操作缺陷;
• 存储过程/函数在 MySQL 8.0 中仍是内存泄漏高发区,执行 SELECT Routine_schema, Routine_type FROM information_schema.Routines WHERE Routine_schema NOT IN ('mysql','information_schema','performance_schema','sys'); 查是否存在大量自定义逻辑。
真正难处理的是那些“不释放”的内存——比如某个连接建了但没 close,sort_buffer_size 就一直挂着;或者 performance_schema 的 history 表被设得过大又没关 consumer,启动即锁死几百 MB。这些不会在配置里一眼看出,得进库查、对比 processlist、盯 free 值变化节奏。











