程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL系列:innodb引擎分析之內存管理

MySQL系列:innodb引擎分析之內存管理

編輯:MySQL綜合教程

MySQL系列:innodb引擎分析之內存管理


在innodb中實現了自己的內存池系統和內存堆分配系統,在innodb的內存管理系統中,大致分為三個部分:基礎的內存塊分配管理、內存伙伴分配器和內存堆分配器。innodb定義和實現內存池的主要目的是提供內存的使用率和效率,防止內存碎片和內存分配跟蹤和調試。我們先來看看他們的關系和結構。

以下是它的關系結構圖:

\

上圖中的:

ut_mem_block塊是基礎內存管理

Buddy allocatZ喎?http://www.Bkjia.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功能。
基礎內存管理的方法如下:
ut_malloc_low 分配一個n長度的內存塊,並將分配的塊記錄到ut_mem_block_list當中.
ut_malloc 與ut_malloc_low功能相同,但是會用0初始化所分配的內存。
ut_free 釋放一個分配的內存塊,並將其從ut_mem_block_list當中刪除。
ut_free_all_mem 釋放ut_mem_block_list所有的內存塊並清空ut_mem_block_list
以上函數是支持多線程並發操作的,也就是說是線程安全的。 innodb這樣做的目的是保證所有malloc出去的內存都在 ut_mem_block_list當中,以便管理。 基礎內存管理的結構如下: \

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 allocator
mem_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的性能提升。





  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved