来源:自学PHP网 时间:2015-04-16 10:50 作者: 阅读:次
[导读] 在innodb中实现了自己的内存池系统和内存堆分配系统,在innodb的内存管理系统中,大致分为三个部分:基础的内存块分配管理、内存伙伴分配器和内存堆分配器。innodb定义和实现内存池...
在innodb中实现了自己的内存池系统和内存堆分配系统,在innodb的内存管理系统中,大致分为三个部分:基础的内存块分配管理、内存伙伴分配器和内存堆分配器。innodb定义和实现内存池的主要目的是提供内存的使用率和效率,防止内存碎片和内存分配跟踪和调试。我们先来看看他们的关系和结构。 以下是它的关系结构图:
上图中的: ut_mem_block块是基础内存管理 Buddy allocatZ喎"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcsrHxNq05rvvsOm31sXkxvc8L3A+CjxwPiAgICBtZW1faGVhcMrHxNq05rbRt9bF5Mb3PC9wPgo8aDE+MS67+bShxNq05rncwO08L2gxPgppbm5vZGLW0LXExNq05rfWxeS6zcTatObKzbfFysfNqLn9zbPSu7XEveG5ub340NC53MDto6y+38zltcTKtc/W1Np1dDBtZW0uaLrNdXQwbWVtLmO1sdbQo6zG5NbQ1+7W2NKqtcS+zcrHttRtYWxsb2O6zWZyZWW1xLfi17Cho82ouf3Su7j2wbSx7b3hubnM5cC0udzA7dLRvq231sXktcTE2rTmo6y94bm5zOXI58/Co7oKPHByZSBjbGFzcz0="brush:sql;"> typedef ut_mem_block_struct
{
ulint size; /*这个被分配block的内存大小*/
ulint magic_n; /*节点魔法字,用于校验所用*/
UT_LIST_NODE_T(ut_mem_block_t) mem_block_list; /*block list node,指定prev node和next node*/
};关于block的list定义是个全局的变量,UT_LIST_BASE_NODE_T(ut_mem_block_t)
ut_mem_block_list;所有分配的block都会加入到这个list当中。在ut_malloc_low函数分配内存的时候会将分配的block加入到list当中,在ut_free的时候会所释放的内存所在的block从list当中删除。除了这两个函数以外,innodb还提供ut_free_all_mem函数来释放所有分配的block和统计分配内存的总数ut_total_allocated_memory功能。 2.伙伴分配器innodb的伙伴分配器是基于ut_malloc_low函数之上的内存管理器,在创建伙伴分配器时,innodb会一下用ut_malloc_low开辟一个很大的内存块,然后用伙伴分配来分配这个块的内存使用。innodb的伙伴分配器是基于2的基数为基础的管理方式,其buddy alloc pool的定义如下:struct mem_pool_struct { byte* buf; /*整体内存的句柄*/ ulint size; /*整体内存大小*/ ulint reserved; /*当前分配出去的总内存大小*/ mutex mutex; /*多线程互斥量*/ UT_LIST_BASE_NODE_T(mem_area_t) free_list[64]; /*area_t链表数组,每个数组单元能管理2的i次方内存块列表,i是数组的下标*/ }; struct mem_area_struct { ulint size_and_free; /*area的内存大小(一定是2的次方),最后一个bit表示是否已经释放*/ UT_LIST_NODE_T(mem_area_t) free_list; /*area链表的上下area,因为buddy area是会分裂的,有可能多个*/ };mem_area_t是一个buddy的内存区域,也就是mem_area_struct。以下是一个32位机器管理1024字节内存块的buddy list分布: 每一个area是有mem_area_t头和可分配的内存(memory_buffer)确定的,memory_buffer的长度不小于mem_area_t头的长度,在32位机器上mem_area_t的头应该是16个字节(8字节对齐)。 2.1mem_area_t的分裂在内存分配的过程中,有可能会造成mem_area_t的分裂,还是以上面的例子来说,加入我们要分配一个200字节的内存,这时候伙伴分配器的分配流程是这样的: 1.找到一个离200+sizeof(mem_area_t)最近的2的i次方的数(256),确定i = 8, 2.在free_list[i]的列表中查找是否有空闲的node,如果有,将node职位no free.如果没有,对i + 1层执行查找是否有可用的内存, 3.在上面的例子中,i+1=9,free_list是空的,继续在i+2层找,一次类推,直到找到有node的层,也就是i = 10; 4.首先对10层进行分裂,分裂成两512大小的第9层节点,并从10删除area,在第9层加入2个512的node. 5.然后在对第9层的第一个节点进行分裂,分裂两个大小为256的第8层节点,并从第九层删除,在第8层加入2个节点。 6.将第一个256大小的area分配给对应的操作者,并置为no free标识。 以下是分配了一个200字节的内存池结构:如果分配出去后的area_t会从free_list[i]链表中删除,也就是说在buddy上将是记录的。 2.2mem_area_t的合并如果200字节分配出去后,使用完毕会归还给buddy allocator,还是拿上面的例子来说,就会发生area合并的情况,步骤如下:1.使用者归还伙伴分配的内存,首先会根据area_t的信息去找到自己的buddy,也就是第8层另外一个没有被分配的area. 2.找到buddy area后,判断buddy area是否是释放状态,如果是,触发合并,将自己和buddy area从第8层删除,合并成一个512大小的第9层area, 3.在重复1 ~ 2步,又会将自己和第九层另外一个buddy area合并成一个1024大小的第10层area. 2.3buddy allocator的接口函数:mem_pool_create 构建一个buddy allocatormem_area_alloc 用buddy allocator分配一块内存 mem_area_free 将一块内存归还给buddy allocator mem_pool_get_reserved 获得buddy allocator已经使用的内存大小 3内存分配堆(memory heap)innodb中的内存管理最终的体现形式是mem_heap_t内存分配与管理,所有关于内存分配的操作都会调用mem_heap的API方法,mem_heap_t的结构定义如下:struct mem_block_info_struct { ulint magic_n; /*魔法字*/ char file_name[8]; /*分配内存的文件*/ ulint line; /*分配内存的文件所在行*/ ulint len; /*block的长度*/ ulint type; /*依赖的底层分配类型,有DYNAMIC、BUFFER、BTR_SEARCH三种类型*/ ibool init_block; /*是否是外部分配的内存块*/ ulint free; /*被占用的空间大小*/ ulint start; /*可分配内存的起始位置*/ byte* free_block; /*备用block,仅仅在BTR_SEARCH方式可用*/ UT_LIST_BASE_NODE_T(mem_block_t) base; UT_LIST_NODE_T(mem_block_t) list; };备注:mem_block_info_struct/mem_block_info_t/mem_block_t/mem_heap_t是等价 mem_heap_t的内存结构如下: 系统的malloc和free来作为内存管理。MySQL默认的是系统管理内存方式,一些有经验的DBA会使用系统的管理内存方式+TMalloc来做内存优化,借助TMalloc高效的内存管理方式实现MySQL的性能提升。 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com