| API | 用途 | 釋放時機 | 範例 |
emalloc()/efree() | 請求級記憶體 | 請求結束 (RSHUTDOWN) 自動釋放 | 變數值、暫存陣列、模板編譯結果 |
pemalloc()/pefree() | 持久記憶體 | SAPI 關閉 (MSHUTDOWN) 釋放 | 資源類型結構、常數表、類別定義、連線池 |
宏定義:pemalloc(size, persistent) 中 persistent=1 走持久分配,0 走請求分配。
錯誤跳躍洩漏示範與 ZendMM 保護
void call_function(const char *fname, int fname_len TSRMLS_DC) {
char *lcase_fname = estrndup(fname, fname_len); // 請求級分配
zend_str_tolower(lcase_fname, fname_len);
if (zend_hash_find(EG(function_table), lcase_fname, fname_len+1, (void**)&fe) == FAILURE) {
zend_execute(fe->op_array TSRMLS_CC);
} else {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined function: %s()", fname);
// longjmp() 直接跳出,efree(lcase_fname) 被略過
}
efree(lcase_fname); // 正常路徑才會執行
}
若無 ZendMM,lcase_fname 記憶體永久洩漏。有 ZendMM 時,請求結束自動回收。
開發者最佳實踐
- 擴展開發**優先使用
emalloc()/efree()**,除非確需跨請求持久。
- 儘量在函式結束前
efree() 釋放大型暫存記憶體,降低請求峰值記憶體。
- 啟用
--enable-debug 編譯 PHP,請求結束會自動報告未釋放的請求級記憶體(洩漏偵測)。
- 避免在擴展中直接呼叫系統
malloc()/free(),繞過 ZendMM 保護。
記憶體洩漏偵測範例
void show_value(int n) {
char *message = emalloc(1024);
sprintf(message, "The value of n is %d\n", n);
php_printf("%s", message);
// 忘記 efree(message)
}
開啟 --enable-debug 後,請求結束輸出:
/cvs/php5/ext/sample/sample.c(33) : Freeing 0x084504B8 (1024 bytes), script=-
=== Total 1 memory leaks detected ===
精確定位洩漏分配位置(檔案、行號、大小),極大提升除錯效率。
- 上一篇文章: PHP 變數內部結構深度解析:zval、zvalue_value 與 8 大資料型別
- 下一篇文章: C# TreeView 聯動選中:父節點選中自動勾選所有子節點完整實現
Copyright ©
程式碼之家 All Rights Reserved