<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在innodb中實現了自己的內存池系統和內存堆分配系統,在innodb的內存管理系統中,大致分為三個部分:基礎的內存塊分配管理、內存伙伴分配器和內存堆分配器。innodb定義和實現內存池的主要目的是提供內存的使用率和效率,防止內存碎片和內存分配跟蹤和調試。我們先來看看他們的關系和結構。 以下是它的關系結構圖: ![](https://box.kancloud.cn/2016-08-17_57b4215ec7170.jpg) 上圖中的: ut_mem_block塊是基礎內存管理 Buddy allocator是內存伙伴分配器 ?mem_heap是內存堆分配器 ## 1.基礎內存管理 innodb中的內存分配和內存釋放是通過統一的結構進行管理,具體的實現在ut0mem.h和ut0mem.c當中,其中最重要的就是對malloc和free的封裝。通過一個鏈表結構體來管理已經分配的內存,結構體如下: ~~~ 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當中,以便管理。 ? 基礎內存管理的結構如下: ![](https://box.kancloud.cn/2016-08-17_57b4215ee2cbf.jpg) ## 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分布: ![](https://box.kancloud.cn/2016-08-17_57b4215f060ae.jpg) 每一個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字節的內存池結構: ![](https://box.kancloud.cn/2016-08-17_57b4215f1a924.jpg) 如果分配出去后的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的內存結構如下: ![](https://box.kancloud.cn/2016-08-17_57b4215f3287e.jpg) 關于mem_heap_t的幾個要點: ? 1.一個mem_block_t最小空間不小于64字節,標準的大小是8KB,在非MEM_HEAP_BUFFER模式下分配的空間不大于page size - 200(page size一般為16KB) ? 2.mem_heap_t有三種類型,分別是DYNAMIC、BUFFER、BTR_SEARCH,在DYNAMIC模式下都是基于buddy allocator進行mem_block_t分配的,在BTR_SEARCH模式下,使用free_block來作為內存分配,在BUFFER模式下比較復雜,如果分配的內存大小< page size的一半時,使用buddy alloc,否則使用buf_frame的內存分配方式(這個是屬于buf0buf.XX里面的方式,還未開始分析)。 ? 3.mem_heap_t在分配新的mem_block_t的時候一定是分配一個heap最后節點大小的兩倍,如果分配的大小超過MEM_MAX_ALLOC_IN_BUF(相當于一個page size)的時候,heap 類型判斷,在不是DYNAMIC模式下,最大就是一個MEM_MAX_ALLOC_IN_BUF大小。如果其他模式下就是設置成MEM_BLOCK_STANDARD_SIZE標準大小,在這些限制外,如果需要分配的內存大于這些限制,以分配內存大小為準進行mem_block_t分配。分配好的mem_block_t總是加入到heap base list的最后,也就是heap堆棧的頂端。 ? 4.mem_heap_t在釋放mem_block_t時候總是從頂端開始釋放,直到不能釋放為止(mem_block_t沒有被使用者歸還)。在mem_block_t釋放的時候也是需要參考DYNAMIC、BUFFER、BTR_SEARCH類型進行相對于的歸還規則(和2要點是相對應的)。 **mem_heap_t函數方法說明:** mem_heap_create ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?用DYNAMIC模式創建一個mem_heap_t mem_heap_create_in_buffer ? ? ? ? ? ? ? ? ? ? ? ?用BUFFER模式創建一個mem_heap_t mem_heap_create_in_btr_search ? ? ? ? ? ? ? ? 用BTR_SEARCH模式創建一個mem_heap_t mem_heap_free ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?釋放mem_heap_t對象 mem_alloc ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?創建在MEM_HEAP_DYNAMIC模式下,并分配一塊指定大小的內存(在這種方式下mem_heap_t只會有一個mem_block_t) mem_free ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?歸還mem_heap_t分配的內存,并釋放mem_heap_t mem_heap_alloc ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 在指定的mem_heap_t上分配一塊內存 mem_heap_get_heap_top ? ? ? ? ? ? ? ? ? ? ? ? ? ?獲得heap頂端塊可使用內存的地址 mem_heap_empty ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?清空指定的mem_heap_t mem_heap_get_top ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 獲得heap頂部的指定n大小的mem_block_t指針 mem_heap_free_top ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?釋放heap頂部N大小的mem_block_t塊 ## 4總結 innodb提供內存池和heap分配方式來統一管理內存,最主要的目的是提高內存的率。在MySQL-5.6的版本中,innodb提供兩種選擇,一種是使用innodb提供的內存池管理內存,還有一種是提供系統的malloc和free來作為內存管理。MySQL默認的是系統管理內存方式,一些有經驗的DBA會使用系統的管理內存方式+TMalloc來做內存優化,借助TMalloc高效的內存管理方式實現MySQL的性能提升。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看