关于mysql占用内存不释放的实验结论
一、现象
可能大家都遇到过这么一种现象。MySQL占用着内存不释放,然后还时不时的一点点增加。
二、问题排查
结合官方文档 https://dev.mysql.com/doc/refman/5.7/en/memory-use.html 和 percona文档 https://www.percona.com/blog/2018/06/28/what-to-do-when-mysql-runs-out-of-memory-troubleshooting-guide/
得出以下MySQL占用内存的计算方法
--查看每个线程占用多少内存,然后乘以正在运行的线程(也就是排查sleep的)。 SELECT ( ( @@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size + @@join_buffer_size + @@binlog_cache_size + @@thread_stack + @@max_allowed_packet + @@net_buffer_length ) ) / (1024*1024) AS MEMORY_MB; --查看MySQL全局占用多少内存 select (@@innodb_buffer_pool_size +@@innodb_log_buffer_size +@@key_buffer_size) / 1024 /1024 AS MEMORY_MB; --查看performance_schema占用多少内存 SELECT SUBSTRING_INDEX(event_name,'/',2) AS code_area, sys.format_bytes(SUM(current_alloc)) AS current_alloc FROM sys.x$memory_global_by_current_bytes GROUP BY SUBSTRING_INDEX(event_name,'/',2) ORDER BY SUM(current_alloc) DESC; --查看 memory 存储引擎占用多少内存 select sum(max_data_length)/1024/1024 as MEMORY_MB from tables where engine='memory';
再把上面的结果相加,就是MySQL当前占用的内存大小。但问题是算出来的结果比实际的小了很多。但如果拿历史最大连接数去算的话,结果是差不多的。所以,就在怀疑,MySQL是否有一个内存的“高水位“。因此带着疑问做了以下实验
三、实验
操作系统:centos 7.4
MySQL:percona 5.7.23
内存:32G
innodb_buffer_pool_size:8G
3.1 首先重启MySQL,释放掉内存,重启后,innodb_buffer_pool 中有 free_page,这时候,使用 sysbench 生成 8G 数据。全表扫描 sbtest1,把innodb_buffer_pool 占满,观察当前MySQL占用的内存
--全表扫描sbtest1 select count(*) from (select * from sbtest1) a; --查看innodb_buffer_pool情况 select sum(POOL_SIZE),sum(free_buffers),sum(DATABASE_PAGES) from INNODB_BUFFER_POOL_STATS; +----------------+-------------------+---------------------+ | sum(POOL_SIZE) | sum(free_buffers) | sum(DATABASE_PAGES) | +----------------+-------------------+---------------------+ | 524224 | 6537 | 517687 | +----------------+-------------------+---------------------+
因为我设置 innodb_buffer_pool_instance = 8,innodb_lru_scan_depth = 1024。所以 free_page 最大会剩余 8192 个 buffer。
top 观察到当前 MySQL 占用 8.8G左右
3.2 调整线程。thread 增加到50个,然后观察内存。
0.010 * 1024 = 10.24G 左右。内存从 8.8G 增加到 10.24G,等到查询结束,MySQL内存并没有释放回 8.8G
3.3 把 thread 调整到 10个,观察内存
内存并没有增加
3.4 把 thread 调整到 100个,观察内存
0.012 * 1024 = 12.28(G) 左右
四、结论
从目前的实验结果来看,mysql 会把内存占用不释放,像是有一个历史高水位在那里,比如说,我历史跑过最大连接数 50 个,mysqld占用了 10.24G内存,接下来跑 10个连接数的时候,则内存不会增加。最后跑了100个连接数,内存又增加到12.28G。然后就一直保持在12.28G。
该结论纯属由实验得出的,可能有错误,偏差的地方。如果有朋友觉得结论有错误,或者觉得以偏概全,可以联系 QQ:505701092。欢迎一起讨论或者指正,谢谢!