0%

MySQL内存使用分析

mysqld的内存使用策略

mysqld启动前状态:OS总内存1985MB,已使用280MB,空闲941MB,Swap空间未使用

1
[root@bogon ~]# ps -ef | grep mysqld
2
root      69294  68350  0 09:35 pts/0    00:00:00 grep mysqld
3
[root@bogon ~]# free -m
4
              total        used        free      shared  buff/cache   available
5
Mem:           1985         280         941           8         763        1543
6
Swap:          2047           0        2047

buffer_pool配置的大小是512MB

1
[root@bogon ~]# cat /etc/my.cnf | grep innodb_buffer_pool_size
2
innodb_buffer_pool_size=512m

mysqld启动后:内存使用增加至478MB,增加了198MB,Swap无变化,buff/cache增长了12MB

1
[root@bogon ~]# ps -ef | grep mysqld
2
root      69315      1 21 09:36 pts/0    00:00:01 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/mysql_data --pid-file=/mysql_data/rhel6.pid
3
mysql     69628  69315  8 09:36 pts/0    00:00:00 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/mysql_data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=error.log --pid-file=/mysql_data/rhel6.pid --socket=/mysql_data/mysql.sock --port=3306
4
root      69663  68350  0 09:37 pts/0    00:00:00 grep mysqld
5
[root@bogon ~]# free -m
6
              total        used        free      shared  buff/cache   available
7
Mem:           1985         478         731           8         775        1345
8
Swap:          2047           0        2047

备注:

total:内存总数

used:已经使用的内存数

free:空闲的内存数

shared:多个进程共享的内存总额

buffers:系统分配但未被使用的buffers大小

cached:Page 系统分配但未被使用的cache大小

使用TOP命令观察mysqld进程的内存使用,看到常驻内存占用211MB,虚拟内存1506MB

1
iB Mem :  2033528 total,   740804 free,   498444 used,   794280 buff/cache
2
KiB Swap:  2097148 total,  2097148 free,        0 used.  1369180 avail Mem 
3
4
   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                               
5
 69628 mysql     20   0 1541944 216396   7116 S  0.0 10.6   0:00.56 mysqld

备注:

PR:优先级

NI:nice值,负值表示高优先级,正值表示低优先级

VIRT:虚拟内存大小

RES:常驻内存大小,是进程当前使用的内存大小,包含其他进程的共享内存,不包括swap out

SHR:共享内存大小

查看启动后buffer pool的情况

1
mysql> SHOW variables LIKE 'innodb_buffer_pool_size';
2
+-------------------------+-----------+
3
| Variable_name           | Value     |
4
+-------------------------+-----------+
5
| innodb_buffer_pool_size | 536870912 |
6
+-------------------------+-----------+
7
1 row in set (0.00 sec)
8
9
mysql> SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_total';
10
+--------------------------------+-------+
11
| Variable_name                  | Value |
12
+--------------------------------+-------+
13
| Innodb_buffer_pool_pages_total | 32764 |
14
+--------------------------------+-------+
15
1 row in set (0.03 sec)
16
17
mysql> SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_free';
18
+-------------------------------+-------+
19
| Variable_name                 | Value |
20
+-------------------------------+-------+
21
| Innodb_buffer_pool_pages_free | 30142 |
22
+-------------------------------+-------+
23
1 row in set (0.01 sec)

sys schema中提供了直接查看内存使用的VIEW,当然前提是要先开启performance_schema中的对应instrument和consumer,好在sys提供了存储过程帮我们一键开启:

1
CALL sys.ps_setup_enable_instrument('wait');
2
CALL sys.ps_setup_enable_instrument('stage');
3
CALL sys.ps_setup_enable_instrument('statement');
4
CALL sys.ps_setup_enable_consumer('current');
5
CALL sys.ps_setup_enable_consumer('history_long');

开启以后,查看memory_global_total即可

1
mysql> select * from sys.memory_global_total;
2
+-----------------+
3
| total_allocated |
4
+-----------------+
5
| 132.01 MiB      |
6
+-----------------+
7
1 row in set (0.01 sec)

为了测试内存波动,现把官方的测试库load进去:

1
[root@bogon test_db-master]# mysql -uroot -p123456 < employees.sql
2
mysql: [Warning] Using a password on the command line interface can be insecure.
3
INFO
4
CREATING DATABASE STRUCTURE
5
INFO
6
storage engine: InnoDB
7
INFO
8
LOADING departments
9
INFO
10
LOADING employees
11
INFO
12
LOADING dept_emp
13
INFO
14
LOADING dept_manager
15
INFO
16
LOADING titles
17
INFO
18
LOADING salaries
19
data_load_time_diff
20
00:01:08
21
[root@bogon test_db-master]#

再次查看OS层面的内存使用情况,发现常驻内存占用409MB(增加了198MB),虚拟内存1544MB(增加了38MB)

1
KiB Mem :  2033528 total,   286280 free,   699384 used,  1047864 buff/cache
2
KiB Swap:  2097148 total,  2097148 free,        0 used.  1165152 avail Mem 
3
4
   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                               
5
 69628 mysql     20   0 1580688 418448   9284 S  0.0 20.6   1:05.71 mysqld

再次查看buffer pool和内存的使用情况,看到free page减少至22818(减少了7324个page,对应114MB),但sys.memory_global_total查到的仅增加了9MB左右内存(感觉这个VIEW的结果不太准确)

1
mysql> SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_free';
2
+-------------------------------+-------+
3
| Variable_name                 | Value |
4
+-------------------------------+-------+
5
| Innodb_buffer_pool_pages_free | 22818 |
6
+-------------------------------+-------+
7
1 row in set (0.00 sec)
8
9
mysql> select * from sys.memory_global_total;
10
+-----------------+
11
| total_allocated |
12
+-----------------+
13
| 141.07 MiB      |
14
+-----------------+
15
1 row in set (0.00 sec)

从上述现象可以看出:

  • mysqld启动以后,仅在虚拟内存中分配了所需要的地址空间,并没有真正的映射到物理内存上(否则mysqld的内存占用会立即大于innodb_buffer_pool_size设定的512MB),而是在使用过程中再映射到物理内存,如果物理内存(内存+swap)不足了,就会出错甚至退出

Why is MySQL Using Less Memory Than Configured? (文档 ID 1483601.1)

On Linux the operating system is not necessarily physically allocating the memory when it is requested. This is done as generally processes request more memory than it actually will end up using. So by defering the actual allocation of memory, work is reduced and it is possible to allow more processes than would fit into memory if all processes used the full amount of memory requested. Other operating systems uses different strategies, each with its pros and cons.


MySQL的内存分配相关参数

共享内存
1
mysql> select version();
2
+------------+
3
| version()  |
4
+------------+
5
| 5.7.25-log |
6
+------------+
7
1 row in set (0.00 sec)
8
9
mysql> show variables where variable_name in (
10
    -> 'innodb_buffer_pool_size',
11
    -> 'innodb_log_buffer_size',
12
    -> 'innodb_additional_mem_pool_size',
13
    -> 'key_buffer_size',
14
    -> 'query_cache_size'
15
    -> );
16
+-------------------------+-----------+
17
| Variable_name           | Value     |
18
+-------------------------+-----------+
19
| innodb_buffer_pool_size | 134217728 |
20
| innodb_log_buffer_size  | 16777216  |
21
| key_buffer_size         | 8388608   |
22
| query_cache_size        | 1048576   |
23
+-------------------------+-----------+
24
4 rows in set (0.00 sec)
  • innodb_buffer_pool_size:buffer pool的大小,默认值128MB,建议为总内存的80%(InnoDB还要为buffer pool预留一些空间供control structures使用,因此实际大小为设定值的110%左右)
  • innodb_log_buffer_size:log buffer的大小,默认值8MB或16MB
  • key_buffer_size:MyISAM表的索引缓冲区(key cache)大小,默认值8MB

    1,key cache用于缓存MyISAM表的索引块,而MyISAM表的数据块是直接存放于操作系统文件缓存中的

    2,如果大量使用MyISAM引擎的表,可将此值增大至总内存的25%,但不建议太大

    3,调大此参数可以增加MyISAM表BULK INSERT的效率

    4,通过观察状态变量Key_read_requests, Key_reads, Key_write_requests和Key_writes来了解key_buffer_size的设置是否合理,其中Key_reads/Key_read_requests的值应当小于0.1,Key_writes/Key_write_requests的值应当在1左右

    5,key cache的碎片率计算公式如下,Key_blocks_unused是未使用的块数,key_cache_block_size是每个块的大小。下面公式值越大,说明key cache利用率越高,碎片率越小:
    1 - ((Key_blocks_unused * key_cache_block_size) / key_buffer_size)

  • innodb_additional_mem_pool_size:存放数据字典和其它内部结构的内存大小,默认值8MB,它与innodb_use_sys_malloc参数有关联(两个参数在MySQL 5.7.4中被移除)

    该参数被移除的原因:早期操作系统的内存分配器性能和可伸缩性较差,并且当时没有适合多核心CPU的内存分配器。所以InnoDB实现了一套自己的内存分配系统,做为内存系统的参数之一,引入了innodb_additional_mem_pool_size。随着多核心CPU的广泛应用和操作系统的成熟,操作系统能够提供性能更高、可伸缩性更好的内存分配器,包括Hoard、libumem、mtmalloc、ptmalloc、tbbmalloc和TCMalloc等。InnoDB实现的内存分配器相比操作系统的内存分配器并没有明显优势,所以在MySQL 5.7.4及之后的版本中,移除了innodb_additional_mem_pool_size 和 innodb_use_sys_malloc两个参数,统一使用操作系统的内存分配器

  • query_cache_size:查询缓存的大小,默认值1MB(MySQL 8.0.3中被移除)

    该参数被移除的原因:整个查询缓存功能被移除

线程私有内存
1
mysql> select version();
2
+------------+
3
| version()  |
4
+------------+
5
| 5.7.25-log |
6
+------------+
7
1 row in set (0.00 sec)
8
9
mysql> show variables where variable_name in (
10
    -> 'read_buffer_size',
11
    -> 'read_rnd_buffer_size',
12
    -> 'sort_buffer_size',
13
    -> 'join_buffer_size',
14
    -> 'binlog_cache_size',
15
    -> 'binlog_stmt_cache_size',
16
    -> 'bulk_insert_buffer_size',
17
    -> 'thread_stack',
18
    -> 'net_buffer_length',
19
    -> 'myisam_sort_buffer_size',
20
    -> 'preload_buffer_size'
21
    -> );
22
+-------------------------+----------+
23
| Variable_name           | Value    |
24
+-------------------------+----------+
25
| binlog_cache_size       | 32768    |
26
| binlog_stmt_cache_size  | 32768    |
27
| bulk_insert_buffer_size | 8388608  |
28
| join_buffer_size        | 262144   |
29
| myisam_sort_buffer_size | 8388608  |
30
| net_buffer_length       | 16384    |
31
| preload_buffer_size     | 32768    |
32
| read_buffer_size        | 131072   |
33
| read_rnd_buffer_size    | 262144   |
34
| sort_buffer_size        | 262144   |
35
| thread_stack            | 262144   |
36
+-------------------------+----------+
37
11 rows in set (0.00 sec)
38
39
mysql> show variables where variable_name in (
40
    -> 'max_heap_table_size',
41
    -> 'tmp_table_size'
42
    -> );
43
+---------------------+----------+
44
| Variable_name       | Value    |
45
+---------------------+----------+
46
| max_heap_table_size | 16777216 |
47
| tmp_table_size      | 16777216 |
48
+---------------------+----------+
49
2 rows in set (0.00 sec)
  • read_buffer_size:默认128KB,必须是4KB的倍数,具有如下功能:

    1,对MyISAM引擎的表进行顺序读(sequential scan)的缓存区大小

    2,MEMORY引擎表的MEMORY BLOCK SIZE大小

    3,各种引擎的表在执行ORDER BY排序操作时,用于缓存索引数据的临时文件的大小

    4,各种引擎的分区表在执行BULK INSERT时所使用的缓存区大小

    5,用于缓存各种引擎的表的子查询结果集的缓存区大小

  • read_rnd_buffer_size:默认256KB,具有如下功能:

    1,MRR所使用的排序buffer大小

    2,对MyISAM引擎的表进行随机读的缓冲区大小。例如按照某字段的ORDER BY顺序对MyISAM表进行rowid排序时(参与排序的所有字段(包括select与order by字段)长度超过max_length_for_sort_data),会先在Sort Buffer中按照需求进行排序,然后将rowid放入read_rnd_buffer_size管理的缓冲区中按照rowid再排序,最后再用有序的rowid回表,从而将随机读转化为顺序读(类似于MRR)

  • sort_buffer_size:SQL语句用来进行内存排序操作(order by,group by)的buffer大小,默认256KB,过小会导致磁盘排序。如果增大了max_sort_length参数值(限定字段的前N个字节参与排序,尤其是针对BLOB和TEXT类型),则sort_buffer_size值也应当增大
  • binlog_cache_size:存放每个线程自己transaction的binlog的缓存大小,默认32KB,如果有大事务可以调大
  • binlog_stmt_cache_size:存放每个线程自己的transaction中非事务语句的binlog event的缓存大小,默认32KB
  • join_buffer_size:join buffer的大小,在BNL和BKA中,用于缓存驱动表的数据,默认256KB
  • bulk_insert_buffer_size:用于提高MyISAM表的bulk insert操作(INSERT…SELECT,INSERT VALUES(),…,(),LOAD DATA)效率的cache tree大小,默认8MB
  • tmp_table_size:内存临时表的大小上限(其实是由MIN(max_heap_table_size,tmp_table_size)决定的),默认为16MB,超过会转变为磁盘临时表
  • max_heap_table_size:内存表的大小上限,默认16MB
  • preload_buffer_size:预加载索引时分配的缓冲区大小,默认32KB
  • myisam_sort_buffer_size:MyISAM表执行REPAIR TABLE和CREATE/ALTER INDEX时所使用的排序操作的buffer大小,默认8MB
  • thread_stack:每个连接线程被创建时,MySQL给它分配的内存堆栈大小,默认256KB
  • net_buffer_length:connection buffer和result buffer的初始大小,默认16KB,这两个缓冲区最大能够增长至max_allowed_packet参数指定的大小(4MB),SQL执行完后收缩至net_buffer_length参数指定的大小

根据上面的描述,可以使用如下公式大致评估mysql进程可能使用的最大内存量(通常达不到这个值,因为极少可能出现大量线程同时使用内存临时表和bulk insert buffer等)

1
## MOS文档(ID 1483601.1)中给出了如下公式:
2
3
Global Usage = key_buffer_size + query_cache_size + 1.1 * innodb_buffer_pool_size + innodb_additional_mem_pool_size + innodb_log_buffer_size
4
5
Per Thread = thread_stack + 2 * net_buffer_length
6
7
Note: the per query contribution is more or less based on an average query
8
Per Query = "buffer for reading rows" + "sorting" + "full joins" + "binlog cache" + "index preload" + "internal tmp tables"
9
          =  max(read_buffer_size, read_rnd_buffer_size)
10
          +  max(sort_buffer_size/2, "avg queries with scan" * "avg scans with merge" * sort_buffer_size)
11
          + "avg full joins" * join_buffer_size
12
          + "avg binlog cache use" * binlog_cache_size
13
          +  preload_buffer_size
14
          + "avg tmp tables" * min(tmp_table_size, max_heap_table_size)
15
16
Total = "global" + max_used_connections * ("thread" + "query")

MySQL与Hugepage

hugepage介绍
  • 大页内存的原理涉及到操作系统的虚拟地址到物理地址的转换过程。操作系统为了能同时运行多个进程,会为每个进程提供一个虚拟进程空间。为了保证进程能在内存中找到虚拟页对应的实际物理块,需要为每个进程维护一个映像表,即页表。页表记录了每一个虚拟页在内存中对应的物理块号。在配置好了页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号
  • 由于页表是存放在内存中的,这使CPU在每存取一个数据时,都要两次访问内存。第一次时访问内存中的页表,从中找到指定页的物理块号,再将块号与页内偏移拼接,以形成物理地址。第二次访问内存时,才是从第一次所得地址中获得所需数据。因此,采用这种方式将使计算机的处理速度降低近1/2
  • 为了提高地址变换速度,可在地址变换机构中,增设一个具有并行查找能力的特殊高速缓存,即快表(TLB),用以存放当前访问的那些页表项。由于成本的关系,快表不可能做得很大,通常只存放16~512个页表项
  • 现代的计算机系统,都支持非常大的虚拟地址空间(2^32~2^64)。在这样的环境下,页表就变得非常庞大。例如,假设页大小为4K,对占用40G内存的程序来说,页表大小为10M,而且还要求空间是连续的。为了解决空间连续问题,可以引入二级或者三级页表。但是这更加影响性能,因为如果快表缺失,访问页表的次数由两次变为三次或者四次。由于程序可以访问的内存空间很大,如果程序的访存局部性不好,则会导致快表一直缺失,从而严重影响性能。此外,由于页表项有10M之多,而快表只能缓存几百页,即使程序的访存性能很好,在大内存的情况下,快表缺失的概率也很大。但是假设我们将页大小变为1G,40G内存的页表项也只有40,快表完全不会缺失!即使缺失,由于表项很少,可以采用一级页表,缺失只会导致两次访存。这就是大页内存可以优化程序性能的根本原因:提高快表(TLB)的命中率,减少内存访问次数
huge page优势
  • 提高快表(TLB)的命中率,减少内存访问次数
  • hugepage是共享内存,它会被一直pin在内存中,避免被交换
为MySQL开启hugepage(Linux)

InnoDB支持hugepage,可用于buffer pool和additional memory pool。测试环境的MySQL 5.7.25版本中已经没有innodb_additional_mem_pool_size参数,因此这里仅考虑buffer pool

1
mysql> select version();
2
+------------+
3
| version()  |
4
+------------+
5
| 5.7.25-log |
6
+------------+
7
1 row in set (0.01 sec)
8
9
mysql> show variables where variable_name in (
10
    -> 'innodb_buffer_pool_size',
11
    -> 'innodb_additional_mem_pool_size');
12
+-------------------------+-----------+
13
| Variable_name           | Value     |
14
+-------------------------+-----------+
15
| innodb_buffer_pool_size | 536870912 |512MB
16
+-------------------------+-----------+
17
1 row in set (0.00 sec)
18
19
mysql> show global variables like 'large_page%';
20
+-----------------+-------+
21
| Variable_name   | Value |
22
+-----------------+-------+
23
| large_page_size | 0     |
24
| large_pages     | OFF   |
25
+-----------------+-------+
26
2 rows in set (0.01 sec)

为了开启大页,首先建议关闭透明大页;如果如下两条命令的输出都是never,说明已经关闭transparent hugepage

1
[root@rhel6 ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
2
always madvise [never]
3
[root@rhel6 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
4
always madvise [never]

如果上述命令输出不是never,则在/etc/rc.local中追加如下内容(如果是Linux 7.x,则为/etc/rc.d/rc.local),重启后再使用上述命令检查

1
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
2
echo never > /sys/kernel/mm/transparent_hugepage/enabled
3
fi
4
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
5
echo never > /sys/kernel/mm/transparent_hugepage/defrag
6
fi

在/etc/security/limits.conf定义mysql用户的memlock为unlimited

1
mysql soft memlock unlimited
2
mysql hard memlock unlimited

查看mysql用户的属组信息

1
[root@rhel6 ~]# id mysql
2
uid=496(mysql) gid=504(mysql) groups=504(mysql)

编辑/etc/sysctl.conf,添加如下内容

1
vm.hugetlb_shm_group=504   # mysql用户的gid
2
vm.nr_hugepages=512        # 512*2MB=1GB

vm.nr_hugepages定义了hugepage的数量,它应当满足如下公式:
nr_hugepages * Hugepagesize > innodb_buffer_pool_size + innodb_additional_mem_pool_size

正确设置kernel.shmmax和kernel.shmall,编辑/etc/sysctl.conf,添加如下内容

1
kernel.shmmax=1073741824‬    # 1GB
2
kernel.shmall=2097152       # 2097152*4096=8GB

kernel.shmmax:单个共享内存段的最大值(字节),应当大于要分给mysql使用的hugepage大小
kernel.shmall:共享内存总页数,建议为物理内存大小的90%除以PAGE_SIZE(分页大小:getconf PAGE_SIZE),应当大于:要分给mysql使用的hugepage大小/PAGE_SIZE

使上述配置生效,并检查大页是否按照预期配置开启。下面的输出表示OS支持并且已经开启大页功能,页面大小为2MB,共512个页,一共1GB大页内存。如果(AnonHugePages不为0,说明没关透明大页)

1
[root@rhel6 ~]# sysctl -p
2
...
3
[root@rhel6 ~]# cat /proc/meminfo | grep -i huge
4
AnonHugePages:         0 kB
5
HugePages_Total:     512
6
HugePages_Free:      512
7
HugePages_Rsvd:        0
8
HugePages_Surp:        0
9
Hugepagesize:       2048 kB

在my.cnf中增加如下配置,并重启mysqld(这里innodb_buffer_pool_size设定的是512MB)

1
large_pages=ON

查看大页的使用情况

1
##大页已使用512-498=14个,操作系统承诺会分配的大页还有254个,因此预计最大会分配14+254个页,大小为268*2MB=536MB大页内存
2
[root@rhel6 ~]# cat /proc/meminfo | grep -i huge
3
AnonHugePages:         0 kB
4
HugePages_Total:     512        ## 总的大页数量
5
HugePages_Free:      498        ## 未分配的大页数量
6
HugePages_Rsvd:      254        ## OS承诺会分配,但暂时还没分配的大页数量
7
HugePages_Surp:        0
8
Hugepagesize:       2048 kB
9
10
------------------------------------------------------------------------
11
##top输出
12
Mem:   1907580k total,  1706188k used,   201392k free,     8724k buffers
13
Swap:  4095992k total,    27532k used,  4068460k free,   265224k cached
14
15
   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                              
16
66287 mysql     20   0 1628m 184m  11m S  0.0  9.9   0:08.51 mysqld             
17
18
mysql> show global variables like 'large_page%';
19
+-----------------+---------+
20
| Variable_name   | Value   |
21
+-----------------+---------+
22
| large_page_size | 2097152 |2MB,等于Hugepagesize
23
| large_pages     | ON      |
24
+-----------------+---------+
25
2 rows in set (0.00 sec)

执行一个大的SQL查询后,再次查看mysqld内存占用和大页使用情况

1
##大页已使用512-445=67个,操作系统承诺会分配的大页还有201个,因此预计最大会分配67+201个页,大小为268*2MB=536MB大页内存
2
[root@rhel6 ~]# cat /proc/meminfo | grep -i huge
3
AnonHugePages:         0 kB
4
HugePages_Total:     512
5
HugePages_Free:      445
6
HugePages_Rsvd:      201
7
HugePages_Surp:        0
8
Hugepagesize:       2048 kB
9
10
------------------------------------------------------------------------
11
##top输出
12
Mem:   1907580k total,  1755440k used,   152140k free,      192k buffers
13
Swap:  4095992k total,    42760k used,  4053232k free,    18308k cached
14
15
   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                              
16
67078 mysql     20   0 1692m 184m 1664 S  0.3  9.9   0:08.69 mysqld
Troubleshooting

测试innodb_buffer_pool_size大于hugepage的情况:

1
##保持innodb_buffer_pool_size=512M不变,修改/etc/sysctl.cnf中的vm.nr_hugepages=128,使大页总大小为256MB,小于了buffer pool大小
2
[root@rhel6 ~]# service mysqld stop
3
Shutting down MySQL....                                    [  OK  ]
4
[root@rhel6 ~]# sysctl -p
5
...
6
[root@rhel6 ~]# cat /proc/meminfo | grep -i huge
7
AnonHugePages:         0 kB
8
HugePages_Total:     128
9
HugePages_Free:      128
10
HugePages_Rsvd:        0
11
HugePages_Surp:        0
12
Hugepagesize:       2048 kB
13
14
##启动mysqld时,虽然可以成功启动,但是error.log中出现报错信息
15
2019-12-11T09:56:30.182908Z 0 [Note] InnoDB: Initializing buffer pool, total size = 512M, instances = 1, chunk size = 128M
16
2019-12-11T09:56:30.193825Z 0 [Warning] InnoDB: Failed to allocate 138412032 bytes. errno 12
17
2019-12-11T09:56:30.193969Z 0 [Warning] InnoDB: Using conventional memory pool
18
2019-12-11T09:56:30.201059Z 0 [Warning] InnoDB: Failed to allocate 138412032 bytes. errno 12
19
2019-12-11T09:56:30.201139Z 0 [Warning] InnoDB: Using conventional memory pool
20
2019-12-11T09:56:30.207174Z 0 [Warning] InnoDB: Failed to allocate 138412032 bytes. errno 12
21
2019-12-11T09:56:30.207282Z 0 [Warning] InnoDB: Using conventional memory pool
22
2019-12-11T09:56:30.218470Z 0 [Note] InnoDB: Completed initialization of buffer pool
23
24
[root@rhel6 ~]# cat /proc/meminfo | grep -i huge
25
AnonHugePages:         0 kB
26
HugePages_Total:     128
27
HugePages_Free:      119
28
HugePages_Rsvd:       61
29
HugePages_Surp:        0
30
Hugepagesize:       2048 kB
31
32
##执行大查询后,大页有被使用的情况,说明即使大页比buffer pool小,也可以使用大页
33
[root@rhel6 ~]# cat /proc/meminfo | grep -i huge
34
AnonHugePages:         0 kB
35
HugePages_Total:     128
36
HugePages_Free:       67
37
HugePages_Rsvd:        9
38
HugePages_Surp:        0
39
Hugepagesize:       2048 kB

reference

https://dev.mysql.com/doc/refman/5.7/en/optimizing-memory.html

How to estimate how much memory MySQL uses (文档 ID 1359675.1)

Why is MySQL Using Less Memory Than Configured? (文档 ID 1483601.1)