云服务器中MySQL进程常驻内存占用大,如何查看和释放?

MySQL 进程内存占用高是云服务器常见的性能问题,通常由配置不当、查询效率低或连接数过多引起。以下是系统化的排查与优化步骤:


一、查看 MySQL 内存占用情况

1. 查看 MySQL 进程实际内存使用

# 查看 mysqld 进程的 RSS(常驻内存)和 VSZ(虚拟内存)
ps aux | grep mysqld
top -p $(pgrep mysqld)
  • RSS:实际物理内存占用(重点关注)
  • VSZ:虚拟内存映射大小(包含未使用的部分,参考意义较小)

2. 查看 MySQL 内部内存分配

登录 MySQL 后执行:

-- 查看全局内存使用情况
SHOW GLOBAL STATUS LIKE 'InnoDB_buffer_pool_size';
SHOW GLOBAL STATUS LIKE 'Key_buffer_size';
SHOW GLOBAL STATUS LIKE 'query_cache_size';

-- 查看当前连接数及每个连接的内存估算
SELECT * FROM information_schema.processlist;

-- 查看 InnoDB 缓冲池命中率
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';

3. 使用 Percona Toolkit 深入分析(推荐)

pt-memory-advisor          # 建议合理内存配置
pt-query-digest            # 分析慢查询
pt-mysql-summary           # 生成 MySQL 状态摘要

二、常见原因及解决方案

✅ 1. InnoDB Buffer Pool 过大

现象:innodb_buffer_pool_size 设置过大(如超过服务器内存的 70%)

检查:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

解决:

  • 一般建议设置为服务器总内存的 50%~70%
  • 修改 /etc/my.cnf 或 /etc/mysql/my.cnf:
    [mysqld]
    innodb_buffer_pool_size = 2G   # 根据实际内存调整
    innodb_buffer_pool_instances = 8  # 多实例提升并发性能
  • 重启 MySQL 生效:
    systemctl restart mysql

💡 注意:MySQL 5.6+ 支持动态调整 innodb_buffer_pool_size,无需重启:

SET GLOBAL innodb_buffer_pool_size = 2147483648;  -- 2GB

✅ 2. Key Buffer(MyISAM)占用过高

如果大量使用 MyISAM 表,key_buffer_size 可能占用过多内存。

检查:

SHOW VARIABLES LIKE 'key_buffer_size';
SHOW GLOBAL STATUS LIKE 'Key_read_requests%';

解决:

  • 迁移 MyISAM 表到 InnoDB(更推荐)
  • 若必须保留,适当减小:
    key_buffer_size = 64M

✅ 3. 临时表占用内存

大查询或排序操作会产生临时表,可能驻留内存。

检查:

SHOW GLOBAL STATUS LIKE 'Created_tmp%';
  • Created_tmp_disk_tables / Created_tmp_tables 比例过高 → 临时表溢出到磁盘,但前期仍占内存

解决:

[mysqld]
tmp_table_size = 64M
max_heap_table_size = 64M

✅ 4. 连接数过多导致内存累积

每个连接都会分配固定内存(如 read_buffer_size, sort_buffer_size 等)。

检查:

SHOW VARIABLES LIKE '%buffer_size%';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
典型默认值(可能导致内存爆炸): 变量 默认值 说明
read_buffer_size 128K 每连接读取缓冲区
sort_buffer_size 256K 每连接排序缓冲区
join_buffer_size 256K 每连接连接缓冲区
thread_stack 192K 每线程栈空间

计算示例:

假设 max_connections=500,每个连接平均占用 ~1MB 额外内存
则额外内存 ≈ 500 × 1MB = 500MB

解决:

  1. 降低不必要的 buffer 大小:

    [mysqld]
    read_buffer_size = 128K
    sort_buffer_size = 256K
    join_buffer_size = 256K
    thread_stack = 192K
  2. 限制最大连接数:

    max_connections = 200   # 根据实际需求调整
  3. 使用连接池(应用层):如 HikariCP、Druid 等,避免频繁创建/销毁连接。


✅ 5. 慢查询或未优化查询导致内存泄漏式增长

某些复杂查询可能在执行过程中积累大量中间结果。

解决:

  • 启用慢查询日志:
    slow_query_log = 1
    long_query_time = 2
    slow_query_log_file = /var/log/mysql/slow.log
  • 使用 EXPLAIN 分析慢查询,添加合适索引
  • 定期清理无用数据

✅ 6. 其他内存相关变量检查

SHOW VARIABLES LIKE '%cache%';
SHOW VARIABLES LIKE '%size%';

重点关注:

  • query_cache_size(MySQL 5.7.20+ 已废弃,建议设为 0)
  • table_open_cache
  • open_files_limit

三、快速释放内存技巧

⚠️ 注意:MySQL 没有直接的“释放内存”命令,以下方法需谨慎

方法 说明 风险
FLUSH STATUS 重置统计信息,不释放内存 无
RESET QUERY CACHE 清除查询缓存(旧版本) 仅影响缓存命中
重启 MySQL 彻底释放所有内存 服务中断
调整参数并热加载 如动态调小 buffer pool 需 MySQL 5.6+
-- 动态调整 InnoDB Buffer Pool(MySQL 5.6+)
SET GLOBAL innodb_buffer_pool_size = 1073741824;  -- 1GB

-- 动态调整 Key Buffer(需重启或 MySQL 8.0.3+ 支持)
-- 大多数 buffer 参数需重启生效

📌 最佳实践:通过 my.cnf 调整参数后,重启 MySQL 是最稳妥的方式。


四、自动化监控建议

1. 使用 Prometheus + Grafana 监控

  • 导出器:mysqld_exporter
  • 关键指标:mysql_global_variables_innodb_buffer_pool_pages_data、processlist_threads

2. 简单脚本监控内存趋势

#!/bin/bash
while true; do
    echo "$(date) RSS: $(ps -o rss= -C mysqld)"
    sleep 60
done > /var/log/mysql_memory.log

五、总结 checklist

步骤 操作
🔍 1 确认 RSS 内存是否真的异常(排除监控误差)
🔍 2 检查 innodb_buffer_pool_size 是否过大
🔍 3 检查 max_connections 及各 buffer 参数
🔍 4 分析慢查询,优化 SQL 和索引
🔧 5 调整 my.cnf 参数,重启 MySQL
📊 6 部署监控,持续观察内存趋势

附:推荐的基础 my.cnf 配置(适用于 4GB 内存服务器)

[mysqld]
# 基础配置
user=mysql
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
port=3306

# 内存优化
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 4
key_buffer_size = 64M
tmp_table_size = 64M
max_heap_table_size = 64M

# 连接优化
max_connections = 200
thread_stack = 192K
read_buffer_size = 128K
sort_buffer_size = 256K
join_buffer_size = 256K

# 日志
slow_query_log = 1
long_query_time = 2
log-error=/var/log/mysql/error.log

# 字符集
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

根据实际服务器内存和应用负载,按比例调整上述参数即可有效降低 MySQL 内存占用。

未经允许不得转载:云知识CLOUD » 云服务器中MySQL进程常驻内存占用大,如何查看和释放?