Mysql

刪除記憶體表後 MySQL 不釋放記憶體

  • August 1, 2019

在創建了幾個記憶體引擎表並刪除它們之後,mysqld並沒有釋放所有相應的記憶體。

以下是重現該問題的確切步驟。htop使用(RES 列)觀察記憶體使用情況。

  1. 禁用交換
sudo swapoff -a
  1. 啟動記憶體限制為 4GB 的 mysql
docker run -d -m 4g --shm-size 4g --name mysql_test \
   -e MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql:5.7.25

docker exec -it mysql_test bash

# test to allocate 3G memory in /dev/shm
dd if=/dev/zero of=/dev/shm/dummy bs=1M count=3K
rm /dev/shm/dummy

# create a named pipe for loading data
mkfifo /var/lib/mysql-files/tmp.pipe

# launch mysql client
mysql -uroot
  1. 創建數據庫
create database if not exists mem;
use mem;

-- allow memory table of max size 4GB for this session
set max_heap_table_size = 1024 * 1024 * 1024 * 4;

mysqld記憶體使用:193M

  1. 創建表並載入數據

在 mysql 外殼中:

create temporary table memory_tbl ( idx varchar(1000) ) engine=memory;
load data infile '/var/lib/mysql-files/tmp.pipe' into table memory_tbl (idx);

在另一個終端:

docker exec -it mysql_test sh -c 'yes 0 | head -1048576 > /var/lib/mysql-files/tmp.pipe'

mysqld記憶體使用:1210M

回到 mysql shell 複製表:

create temporary table memory_tbl2 like memory_tbl;
insert into memory_tbl2 select * from memory_tbl;

mysqld記憶體使用量:2227M

再次復製表格:

create temporary table memory_tbl3 like memory_tbl;
insert into memory_tbl3 select * from memory_tbl;

mysqld記憶體使用量:3243M

  1. 刪除表
drop table memory_tbl;

mysqld記憶體使用:3244M

drop table memory_tbl2;

mysqld記憶體使用:3244M

drop table memory_tbl3;

mysqld記憶體使用:2302M

  1. 嘗試分配記憶體

在另一個外殼中:

docker exec -it mysql_test bash

# allocate 1.5G memory
dd if=/dev/zero of=/dev/shm/dummy bs=1M count=1536
rm /dev/shm/dummy

# allocate 2G memory
dd if=/dev/zero of=/dev/shm/dummy bs=1M count=2K
# error occurs
# dd: error writing '/dev/shm/dummy': Cannot allocate memory
rm /dev/shm/dummy

我想知道這是否是 MySQL 伺服器的錯誤。否則,有什麼方法可以讓 MySQL 在不重啟的情況下釋放記憶體mysqld

測試環境:

  • Ubuntu 18.04.1 LTS
  • 核心 4.15.0-34-generic
  • Docker 18.06.1-ce
  • mysql-5.7.25
  • glibc 2.24

根據 MariaDB 伺服器錯誤中的建議Memory not freeed on memory table drop,用 jemalloc 替換預設 glibc 可以解決問題。

以下步驟顯示瞭如何使用 jemalloc 啟動 mysqld:

docker run -it -m 4g --shm-size 4g --name mysql_test \
   -e MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql:5.7.25 bash
apt-get update
apt-get install -y libjemalloc-dev
# adhoc preload jemalloc for ease of testing
# updating /etc/mysql/my.cnf is preferred for permanent setting
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1 docker-entrypoint.sh mysqld

然後我們可以在另一個 shell 中從第 3 步開始進行測試。請注意,mysqld每個 drop table 語句的記憶體使用量下降約 1G。最後,記憶體使用量下降到與初始階段相似的水平,並且/dev/shm可以在其中創建 3G 文件。

更新:

libjemalloc1在這種情況下 ,實際需要的庫是。libjemalloc-dev包含libjemalloc1作為依賴項,這就是它起作用的原因,但代價是安裝了一堆我們不需要的文件。感謝Michael - sqlbot指出這一點。

引用自:https://dba.stackexchange.com/questions/231661