1.Buffer Pool的大小

Buffer Pool本质其实就是数据库的一个内存组件,你可以理解为他就是一片内存数据结构,所以这个内存数据结构肯定是有一定的大小的,不可能是无限大的。这个Buffer Pool默认情况下是128MB

2.数据页:MySQL中抽象出来的数据单位

我们的数据是如何放在Buffer Pool中的
缓存页的描述:这个数据页所属的表空间、数据页的编号、这个缓存页在Buffer Pool中的地址以及别的一些杂七杂八的东西
每个缓存页都会对应一个描述信息,这个描述信息本身也是一块数据。
Buffer Pool中的描述数据大概相当于缓存页大小的5%左右
企业微信截图_16006921117818.png

3.Buffer Poold的初始化

数据库只要一启动,就会按照你设置的Buffer Pool大小,稍微再加大一点,去找操作系统申请一块内存区
域,作为Buffer Pool的内存区域。
然后当内存区域申请完毕之后,数据库就会按照默认的缓存页的16KB的大小以及对应的800个字节左右的描述数据的大小,在Buffer Pool中划分出来一个一个的缓存页和一个一个的他们对应的描述数据
我们怎么知道哪些缓存页是空闲的呢
数据库会为Buffer Pool设计一个free链表,他是一个双向链表数据结构,这个free链表里,每个节点就是一个空闲的缓存页的描述数据块的地址

4.free链表占用多少内存空间

其实就是由Buffer Pool里的描述数据块组成的,你可以认为是每个描述数据块里都有两个指针,一个是free_pre,一个是free_next,分别指向自己的上一个free链表的节点,以及下一个free链表的节点。就可以把所有的描述数据块串成一个free链表
对于free链表而言,只有一个基础节点是不属于Buffer Pool的,他是40字节大小的一个节点,里面就存放了free链表的头节点的地址,尾节点的地址,还有free链表里当前有多少个节点

5.如何将磁盘上的页读取到Buffer Pool的缓存页中

首先,我们需要从free链表里获取一个描述数据块,然后就可以对应的获取到这个描述数据块对应的空闲缓存页
接着我们就可以把磁盘上的数据页读取到对应的缓存页里去,同时把相关的一些描述数据写入缓存页的描述数据块里去

6.你怎么知道数据页有没有被缓存

其实数据库还会有一个哈希表数据结构,他会用表空间号+数据页号,作为一个key,然后缓存页的地址作为value。
当你要使用一个数据页的时候,通过“表空间号+数据页号”作为key去这个哈希表里查一下,如果没有就读取数据页,如果已经有了,就说明数据页已经被缓存了。
企业微信截图_16007560469774.png

7.Buffer Pool中会不会有内存碎片

当然有,
因为Buffer Pool大小是你自己定的,很可能Buffer Pool划分完全部的缓存页和描述数据块之后,还剩一点点的内存,这一点点的内存放不下任何一个缓存页了,所以这点内存就只能放着不能用,这就是内存碎片

8.脏数据/脏页

脏数据:缓存页里的数据和磁盘上的数据页里的数据不一致就
脏页:脏数据存在的缓存页
flush链表:通过缓存页的描述数据块中的两个指针,让被修改过的缓存页的描述数据块,组成一个双向链表
凡是被修改过的缓存页,都会把他的描述数据块加入到flush链表中去,flush的意思就是这些都是脏页,后续都是要flush刷新
到磁盘上去的
企业微信截图_16007638381581.png

9.flush链表构造的伪代码演示

当你更新缓存页的时候,通过变换缓存页中的描述数据块的flush链表的指针,就可以把脏页的描述数据块组成
一个双向链表,也就是flush链表,而且flush链表的基础节点会指向起始节点和尾巴节点
这个flush链表,就可以记录下来哪些缓存页是脏页了
image.png

如果Buffer Pool中的缓存页不够了怎么办

淘汰掉一些缓存数据
把一个缓存页里被修改过的数据,给他刷到磁盘上的数据页里去,然后这个缓存页就可以清空了,
让他重新变成一个空闲的缓存页
LRU链表
这个所谓的LRU就是Least Recently Used,最近最少使用的意思
从磁盘加载一个数据页到缓存页的时候,就把这个缓存页的描述数据块放到LRU链表头部去
只要查询或者修改了这个缓存页的数据,也要把这个缓存页挪动到LRU链表的头部去,也就是说最近被访问过的缓存页,一定在LRU链表的头部