內存管理

背景

內存管理不恰當,會有造成大量內存碎片、內存分配效率低、內存實際使用率低。在程序運行中,這些問題會導致程序無法持久正常運行,於服務器技術而言更是如此。

目標

內存管理可以分爲三個層次,自底向上分別是:

  • 操作系統內核的內存管理
  • 使用系統調用維護的內存管理算法
  • 在上一步基礎上,根據應用程序本身的程序特性進行優化, 比如使用引用計數、內存池方式等

本文我們主要討論第二步的使用系統調用維護的內存管理算法

對於需要持久運行的程序而言,內存管理十分重要,一個優秀的內存管理策略應該具有如下特性:

  • 分配速度儘可能快
  • 內存碎片儘可能少
  • 內存實際使用率高

memcached內存管理機制

memcached是一個知名的高效的分佈式內存cache,默認使用SlabAllocation機制管理內存,其主要思想是按照預先規定的大小,將分配的內存分割成特定長度的塊以存儲相應長度的key-value數據記錄,以完全解決內存碎片問題。

Slab和Chunk

memcached內存結構圖

slab是memcached一次申請內存的最小單位。memcached啓動時使用參數-m指定其可用內存,但並不是啓動時所有的內存就全部分配出去了,只有在需要時纔會去申請,而且每次申請一定是一個slab。Slab的大小固定爲1M(1048576 Byte)。

一個slab由若干個大小相等的chunk組成。每個chunk中都保存了一個item結構體、一對key和value。

雖然在同一個slab中chunk的大小相等的,但是在不同的slab中chunk的大小並不一定相等,在memcached中按照chunk的大小不同,可以把slab分爲很多種類(class)。

在啓動memcached的時候可以通過-vv來查看slab的種類:

$ memcached -vv
slab class 1: chunk size 80 perslab 13107
slab class 2: chunk size 104 perslab 10082
slab class 3: chunk size 136 perslab 7710
slab class 4: chunk size 176 perslab 5957
slab class 5: chunk size 224 perslab 4681
slab class 6: chunk size 280 perslab 3744
slab class 7: chunk size 352 perslab 2978
slab class 8: chunk size 440 perslab 2383
slab class 9: chunk size 552 perslab 1899
slab class 10: chunk size 696 perslab 1506
slab class 11: chunk size 872 perslab 1202
slab class 12: chunk size 1096 perslab 956
slab class 13: chunk size 1376 perslab 762
.
.
.

向memcached添加item時,memcached首先會根據item大小,根據chunk size向上取整,來選擇接近的slab class。例如,item大小爲156,向上取最小的chunk size爲176.

memcached採取SlabAllocation策略,一次向系統申請1M空間內存作爲slab。slab根據其chunk size分割成等大的內存塊chunk,每個chunk都可以存儲一個item。memcached內存分配做到了一次申請大量空間,分割多塊給小對象多次使用,大大降低了向操作系統申請內存的時間,大部分內存管理機制都會用到這個策略。

其次,memcached將slab按chunk size分組,將每一個slab內部按chunk size分割成固定大小的內存塊。固定大小的chunk,回收之後還可以用於下一次item的存儲,內存的分佈情況不會變的錯綜複雜,有利於減少內存碎片。chunk size遞增策略,每一次item都向上取到最接近的chunk size對應的slab來存儲,有利於提高其實際內存利用率

Redis內存管理機制

Redis默認使用jemalloc作爲內存分配器。jemalloc 是一個通用的 malloc(3)實現,它強調了分段迴避和可伸縮併發支持。jemalloc 在 2005 年首次作爲 FreeBSD libc 分配器使用,2010年,jemalloc 的功能延伸到如堆分析和監控/調優等。現代的 jemalloc 版本依然集成在 FreeBSD 中。

jemalloc機制相對memcached的SlabAllocation策略來說比較複雜,這裏不做詳細介紹,詳情可參考本文列出的參考文檔。

類似的,對jemalloc策略總結如下:

  • 一次向系統申請大內存4M(chunk),供之後多次使用
  • 將控制的內存分成不同大小的小內存塊(bins),重複使用
  • 存放對象時,向上找到最接近size的bin對應的空閒內存塊來存儲
  • 每個線程有自己的獨立空間tcache,將內存劃分爲arena供線程使用,減少線程間的互斥訪問

前三條策略的思想與memcached的SlabAllocationc策略所蘊含的思想一致,第四條策略是針對多線程加速的優化。

參考資料

內存優化總結:ptmalloc、tcmalloc和jemalloc

memcached的內存管理機制

jemalloc和內存管裏

A Scalable Concurrent malloc(3) Implementation for FreeBSD

jemalloc內存分配器詳解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章