閱讀315 返回首頁    go 阿裏雲 go 技術社區[雲棲]


php之內存管理基礎

用 C 語言編程時,開發者要手工地進行內存管理。因為 PHP 經常用作 Web 服務器的模塊,內存管理與預防內存泄漏緊密關聯。此外要知道 PHP 可能用於線程環境中,這意味著全局變量可能導致競爭狀況。有關線程內全局數據處理的信息請參見作為線程隔離設施的 線程安全的資源管理器

此外,Zend 引擎要麵對一個十分特殊的使用模式:在一段比較短的時間內,許多 zval 結構大小的內存塊和其他的小內存塊被申請又再被釋放。PHP 的內存管理也很重視 memory_limit(內存限製)

為了滿足以上的需求,Zend 引擎提供為了處理請求相關數據提供了一種特殊的內存管理器。請求相關數據是指隻需要服務於單個請求,最遲會在請求結束時釋放的數據。擴展開發者主要接觸下表中列出的慣例。雖然一些所提供的便捷功能是用宏實現的,但在本文中會象函數一樣對待。

主要的內存 APIs 原型 說明 void *emalloc(size_t size) 分配 size 字節的內存。 void *ecalloc(size_t nmemb, size_t size) 給 nmemb 元素分配 size 字節的緩衝區並初始化為零。 void *erealloc(void *ptr, size_t size) 修改使用 emalloc 分配的緩衝區 ptr 的大小為 size 字節。 void efree(void *ptr) 釋放 ptr 指向的緩衝區。緩衝區必須是由 emalloc 分配的。 void *safe_emalloc(size_t nmemb, size_t size, size_t offset) 分配緩衝區來存放每塊大小為 size 字節的 nmemb 塊,並附加 offset 字節。類似於 emalloc(nmemb * size + offset),但增加了針對溢出的特殊保護。 char *estrdup(const char *s) 分配一個可存放 NULL 結尾的字符串 s 的緩衝區,並將 s 複製到緩衝區內。 char *estrndup(const char *s, unsigned int length) 類似於 estrdup,但 NULL 結尾的字符串長度是已知的。

Note和與 C 標準庫相似的部分不同,如果分配請求的內存出錯,Zend 引擎的內存管理函數不會返回 NULL 值,而會跳出並中止當前請求。

如上所述,防止有內存泄漏並盡可能快地釋放所有內存是內存管理的重要組成部分。因為安全原因,在請求結束時, Zend 引擎會釋放所有由上麵提到的 API 所分配的內存。如果 PHP 使用 --enable-debug 配置選項進行構建,這將產生一個警告。

Example #1 PHP 的泄漏報警

ZEND_FUNCTION(leak)
{
    long leakbytes = 3;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &leakbytes) == FAILURE) {
        return;
    }

    emalloc(leakbytes);
}

以上例程的輸出類似於:

[Thu Oct 22 02:14:57 2009]  Script:  '-'
/home/johannes/src/PHP_5_3/Zend/zend_builtin_functions.c(1377) :  Freeing 0x088888D4 (3 bytes), script=-
=== Total 1 memory leaks detected ===

Note當使用 PHP 變量時,需要確認變量的內存要使用 emalloc 來分配,並注意引用計數。相關細節請查看 變量的使用

Note內存泄漏檢測僅可以發現由 emalloc 分配內存塊導致的泄漏。為進行深層分析,建議使用內存檢測器,如 valgrind 或 libumem 等。要簡化此分析,可在 PHP 啟動時通過設置環境變量 USE_ZEND_ALLOC=0 來禁用 PHP 的內存管理器。

最後更新:2017-04-03 05:38:56

  上一篇:go php之substr()詳解
  下一篇:go php之unset()詳解