首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 內存管理深度解析:Zend MM 核心數據結構與分配策略詳解

     編輯:PHP 相關知識

PHP 內存管理分為兩大層面:面向應用層的引用計數、寫時復制,及底層 Zend Memory Manager (Zend MM) 對可用內存的管理與分配。本文聚焦 Zend MM 核心邏輯,揭秘鮮為人知的數據結構、快取機制與大小塊內存差異化策略。作者:Laruence (惠新宸)。

🎯 核心數據結構:zend_mm_heap

zend_mm_heap 結構

Zend MM 將內存劃分為 小塊 與 大塊 兩類,差異化處理:

  • 小塊內存:最高頻使用,追求極致性能,引入 快取機制
  • 大塊內存:追求穩健,盡量避免碎片浪費

⚡ 小塊內存快取機制

小塊內存快取

目標:一次定位即完成分配。關鍵結構 free_buckets 為定長數組,存儲 ZEND_MM_NUMBER_BUCKET 個 zend_mm_free_block。

💡 設計巧思:free_buckets 內存佈局優化

未使用的 bucket 僅需 next_free_block、prev_free_block 兩指針。為節省內存,PHP 未分配完整 zend_mm_free_block 結構,而是僅分配雙指針空間:

#define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
    (zend_mm_free_block*)((char*)&heap->free_buckets[index * 2] + \
    sizeof(zend_mm_free_block*) * 2 - \
    sizeof(zend_mm_small_free_block))

運行時保證僅訪問 prev/next 兩指針,避免越界讀寫。

🌳 大塊內存管理:鍵樹 + 雙向鏈表混合結構

大塊內存結構

索引計算:最高位 1 的位序

#define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)

zend_mm_high_bit 獲取 size 二進制中最高位 1 的位序(對應匯編指令 bsr)。注意:TIPI 專案曾誤解釋為「1 的個數 - 1」。

分配邏輯:zend_mm_search_large_block

  1. 計算 true_size 對應 index
  2. 位圖 large_free_bitmap 快速判斷是否存在可用塊
  3. 若 free_buckets[index] 有可用塊,從雙向鏈表查找
  4. 按 true_size 二進制位從高到低遍歷鍵樹:
      - 當前位為 1 → 進入 child[1]
      - 當前位為 0 → 先嘗試 child[0],無則進 child[1] 找最小可用塊
  5. 若未找到,在位圖中尋找下一個非空 bucket,並取其鍵樹中最小塊(best-fit)
best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
while ((p = p->child[p->child[0] != NULL])) {
    if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit))
        best_fit = p;
}

此邏輯確保在大塊區域快速定位最合適內存,兼顧速度與碎片控制。

🔄 rest_buckets:殘留內存緩衝區

雙向鏈表結構,暫存分配後剩餘的小塊內存,避免頻繁插入 free_buckets 造成性能抖動。TIPI 專案曾誤描述為「只有兩個元素的數組」。


理解 Zend MM 內存分配策略,對開發高性能擴展、排查內存洩漏、優化長運行腳本至關重要。英文版文檔 Zend MM 亦在持續完善中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved