nginx reload記憶體碎片問題
相關資料
jemalloc、pmap、redis、systemtap、記憶體緊縮
問題現象
cache nginx 開啟ip 庫功能 占用700m 記憶體,reload 後記憶體翻倍,無法釋放
root 9186 0.2 7.2 2150680 1786272 nginx master
reload 前 800m reload 後1.7g
根據描述有free,且多次reload 後記憶體不再增長;ip庫使用系統malloc 和 free 沒有使用記憶體池
問題原因
ip 庫malloc 和free 大量緊鄰操作可能導致glibc 記憶體管理合併機制沒有歸還給作業系統;解決方案使用malloc_trim() 函式歸還記憶體給系統。
排查過程
首先驗證是否存在記憶體洩漏
使用systemtap 指令碼 排查沒有存在記憶體洩漏,nginx 確實有釋放
使用pmap pid檢視程序占用記憶體
000000000017a0000 872628k rw---- [ anon ]
***************xx [ zero deleted ]
reload 後, pmap 檢視 從系統角度而言原先分配的記憶體確實還占用著,且又新分配了一段空間
結合ipku的頻繁記憶體malloc 和 free 極有可能是記憶體碎片
000000000017a0000 872628k rw---- [ anon]
***************xx xx xx [ zero deleted ]
00007fa033f930000 782890k rw---- [ anon]
***************xx xx xx [ zero deleted ]
使用glibc 提供的malloc_trim 函式進行記憶體緊縮,記憶體得到釋放。malloc_trim 是 glibc 4.0 以上提供的介面,緊縮為阻塞操作,可能影響服務時間,建議動態介面觸發 擴充套件
c 等語言記憶體碎片如果不用記憶體池,會有碎片率問題:
如何計算記憶體碎片率
redis 是如何計算記憶體碎片率沒有深入研究過。但是像squid 類似的軟體,對malloc 有做一層封裝xmalloc,那麼只需要統計(xmalloc-xfree)獲得squid 內部的分配數 除以 jemalloc 的malloc static分配數 即可得到底層系統庫記憶體碎片率,前提要求只有squid 才用到了jemalloc 採用靜態庫介面yes_jemalloc 而其他so 用的是glibc,算起來會比較準確
深入研究
redis 有記憶體碎片檢視介面,redis4 支援記憶體碎片清理、redis5 出了主動碎片整理v2 更好的記憶體統計報告、jemalloc5.1
記憶體管理 內部碎片和外部碎片
概念 乙個分割槽內部出現的碎片 即被浪費的空間 不能被利用。能明確指出屬於哪個程序 例子 固定分割槽法中,當6kb的程序被分配了10kb的記憶體空間,就有4kb的內部碎片 乙個程序申請43kb的記憶體空間,某些處理器因為限制 比如其體系結構規定只能整除4 8 16 該程序被分配了44kb,就有1kb...
記憶體中,外部碎片與內部碎片
外部碎片,是由於大量資訊由於先後寫入 置換 刪除而形成的空間碎片。為了便於理解,我們將資訊比作貨物,將儲存空間比作倉庫來舉例子。假設,我們有編號為1 2 3 4 5 6的6間倉庫庫房,前天送來了一大宗貨,依次裝入了1 2 3 4 5號倉庫,昨天又因故將4號庫房的貨物運走了,那麼數值上說我們還有兩間空...
malloc free與記憶體碎片
malloc和free大量使用後回造成記憶體碎片,那麼這種碎片形成的機理是什麼?如果機理是申請的記憶體空間大小 太小 所形成的,那麼,申請多大的區域能夠最大限度的避免記憶體碎片呢?這裡的避免不是絕對的避免,只是一種概率 記憶體碎片一般是由於空閒的連續空間比要申請的空間小,導致這些小記憶體塊不能被利用...