mysql占用内存过高的原因,mysql内存占用越来越大

  mysql占用内存过高的原因,mysql内存占用越来越大

  分析场景1:使用sysbench测试数据库场景2:加载大型事务的insert语句;问题突破测试jemalloc场景1:使用sysbench测试数据库场景2:加载大型事务的insert语句;总结:MySQL释放内存了吗?通过gdb调试结论

  在网上MySQL数据库发现一些实例,内存使用量不断增加,连接号断开时内存也不会释放,最终结果被操作系统OOM。

  问题分析模拟两个场景来分析这个问题:

  1场景使用sysbench测试MySQL数据库。断开连接后,使用top检查mysqld进程和内存使用情况。

  将mysql innodb_buffer_pool设置为128M,方便观察内存增长情况。

  启动MySQL后的内存使用量约为150M:

  Sysbench压力测量60秒

  sys bench-d b-driver=MySQL/usr/share/sys bench/OLTP _ read _ only . Lua-MySQL-host=127 . 0 . 0 . 1-MySQL-port=3320-MySQL-db=sb test-MySQL-user=root-MySQL-password=123456-tables=16-table _ size=500000-threads=128-time=60-report-interval=1运行观察内存使用情况:

  内存增加到540M左右,但并没有随着sysbench的断开而释放内存。

  场景2加载一个大事务的insert语句重启MySQL观察内存使用情况,大约需要170M:

  文件大小43M

  文件内容:

  插入虚拟值

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  (1,“这是一个虚拟值”),

  .源文件:

  观察mysql source test.sqlsource完成后的内存使用情况:

  同样,当它占用1G内存时,由于连接断开,内存也不会被释放。

  突破through通过上面两个例子,可以证明MySQL连接断开后内存并没有被释放。

  时间长了会导致记忆增加。查bugs.mysql发现有人提到过这个问题:

  https://bugs.mysql.com/bug.php? id=83047

  ——有人在里面提出了一个负载的大交易,来重现这个问题。

  同样,percona版本也被提及:

  https://bugs.launchpad.net/ubuntu/源代码/mysql-5.7/bug/1710146

  在上面的链接中,有人提到使用jemalloc似乎可以解决这个问题。

  测试jemalloc也是为了测试以上两种场景。jemalloc的使用方法如下:

  yum安装jemalloc

  在mysqld_safe中,在前面添加以下信息:

  export LD _ PRELOAD=/lib 64/libjemalloc . so . 1

  重启mysql实例

  使用pt工具来确认你是否被使用,jemalloc。

  pt-MySQL-summary-S/tmp/MySQL-3320 . sock-user root-password 123456 grep-A 5 内存管理

  显示以下信息,表示使用jemalloc场景1和sysbench数据库启动MySQL后的内存使用情况,约为150M:

  Sysbench压力测量60秒

  sys bench-d b-driver=MySQL/usr/share/sys bench/OLTP _ read _ only . Lua-MySQL-host=127 . 0 . 0 . 1-MySQL-port=3320-MySQL-db=sb test-MySQL-user=root-MySQL-password=123456-tables=16-table _ size=500000-threads=128-time=60-report-interval=1运行观察内存使用情况:

  测时内存增加到550M左右,随着sysbench的断开释放了一部分内存,保持在370M左右。

  场景2加载一个大事务的insert语句重启MySQL观察内存使用情况,大概需要150M:

  源文件:

  观察mysql source test.sqlsource完成后的内存使用情况:

  随着SQL执行的完成,内存被释放到300M。

  从上面的比较可以得出结论,jemalloc内存分配方法确实可以快速释放内存给操作系统,减少系统内存的过度使用和被OOM。

  MySQL到底有没有释放内存?继续分析MySQL的实际执行情况。有没有主动释放内存?内存释放在哪里?

  通过gdb调试,登录mysql中的另一个窗口,执行gdb attach to MySQL process/opt/RH/dev toolset-8/root/bin/GDB-p ` PS-ef grep-w mysqld grep-v grep awk { print $ 2 } `设置断点(GDB) b/

  b connection _ handler _ per _ thread . cc:321

  执行断点2at166ee7f中的c(gdb)c:file/my data/project/MySQL-server/SQL/conn _ handler/connection _ handler _ per _ thread . cc,line321.gdb。

  Continuingmysql客户端源文件mysql source test.sql此时可能需要等待一段时间,因为文件比较大,mysql客户端需要对文件进行解析,在gdb窗口中等待即可,在以下情况发生之前不必执行任何命令:

  gdb) c

  继续。

  [切换到线程0x7fea2b008700 (LWP 29406)]

  线程28“mysqld”命中断点1,dispatch _ command(thd=0x 7 FEA 02819000,com_data=0x7fea2b007c90,command=COM_QUERY)

  at/my data/Project/MySQL-server/SQL/SQL _ parse . cc:1947

  1947自由根(thd- mem_root,MYF(MY _ KEEP _ pre alloc));此时,您可以开始调试并检查MySQL内存使用情况:(gdb) p thd- main_mem_root

  $1={free=0x7fe9c2406020,used=0x7fe9c29b3020,pre_alloc=0x7fea02827020,min_malloc=32,block_size=8160,block_num=863,

  first_block_usage=0,max_capacity=0,allocated_size=844547312,error _ for _ capacity _ exceeded=0 \ 000 ,error_handler=0x14baa8b

  SQL _ alloc _ error _ handler(),m _ psi _ key=8}这里我们看到allocated_size=844547312大约是800M,此时mysqld进程占用的内存:

  源码执行前800M的内存使用量目前约为1.1g。

  输入“n”执行下一个free_root步骤,然后检查内存:

  gdb) n

  1961 thd-profiling . finish _ current _ query();

  (gdb) p thd- main_mem_root

  $2={free=0x7fea02827020,used=0x0,pre_alloc=0x7fea02827020,min_malloc=32,block_size=8160,block_num=4,

  first_block_usage=0,max_capacity=0,allocated_size=8208,error _ for _ capacity _ exceeded=0 \ 000 ,

  error _ handler=0x 14 baa 8 bsql _ alloc _ error _ handler(),m _ psi _ key=8}此时allocated_size=8208,也就是在Mysql层,执行完SQL后已经释放了内存。顶部,看看操作系统:

  这里用的是Jemalloc,内存释放(目前占用内存300M左右)。如果是默认的glibc,则不会释放内存。

  这里也分析一下,内存的释放是在SQL语句的层面,不是在整个事务之后,而是在SQL执行之后。

  退出会话将触发另一个断点。

  当会话退出时,您将收到COM_QUIT命令,然后整个线程的内存将被释放。这时,看看top中mysqld的内存使用情况:

  您将看到,随着会话的退出,内存被释放了大约40M,这是mysql中缓存的源文件的大小。当会话在SQL执行后没有退出时,您可以通过查看性能表来检查线程内存使用情况:

  是的,它正好等于文件的大小。

  Kill也会导致NET:buff被释放。

  测试结束后,如果SQL执行完成,线程会在另一个会话中被杀死,NET:buff也会被释放。这里,NET:buff并没有随着SQL执行的完成而释放。查看官方文档net_buffer_length的介绍:

  大概意思是:

  每个客户端会话线程分配两个缓冲区:连接缓冲区和结果集缓冲区,这些缓冲区可以动态扩大到由max_allowed_packet系统变量指定的字节大小。在执行每个SQL语句后,结果集缓冲区会自动减小到net_buffer_length变量指定的大小。然后文档没有提到连接缓冲区会被释放,也就是说会被缓存,直到连接断开。

  结论mysql会主动释放内存。内存释放是在语句级,而不是在会话级。只有在会话退出后,缓冲区内存才会被释放。kill还会释放会话占用的内存。jemalloc拥有比glibc更好的内存分配机制,可以及时将内存释放给操作系统。

  版权归作者所有:原创作品来自博主小二上九8,转载请联系作者取得转载授权,否则将追究法律责任。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: