php的内存划分,解析PHP中的内存管理,PHP动态分配和释放内存
摘要 內(nèi)存管理對于長期運(yùn)行的程序,例如服務(wù)器守護(hù)程序,是相當(dāng)重要的影響;因此,理解PHP是如何分配與釋放內(nèi)存的對于創(chuàng)建這類程序極為重要。本文將重點探討PHP的內(nèi)存管理問題。
一、 內(nèi)存
在PHP中,填充一個字符串變量相當(dāng)簡單,這只需要一個語句"<?php $str = 'hello world '; ?>"即可,并且該字符串能夠被自由地修改、拷貝和移動。而在C語言中,盡管你能夠編寫例如"char *str = "hello world ";"這樣的一個簡單的靜態(tài)字符串;但是,卻不能修改該字符串,因為它生存于程序空間內(nèi)。為了創(chuàng)建一個可操縱的字符串,你必須分配一個內(nèi)存塊,并且通過一個函數(shù)(例如strdup())來復(fù)制其內(nèi)容。
代碼如下:
{
char *str;
str = strdup("hello world");
if (!str) {
fprintf(stderr, "Unable to allocate memory!");
}
}
由于后面我們將分析的各種原因,傳統(tǒng)型內(nèi)存管理函數(shù)(例如malloc(),free(),strdup(),realloc(),calloc(),等等)幾乎都不能直接為PHP源代碼所使用。
二、 釋放內(nèi)存
在幾乎所有的平臺上,內(nèi)存管理都是通過一種請求和釋放模式實現(xiàn)的。首先,一個應(yīng)用程序請求它下面的層(通常指"操作系統(tǒng)"):"我想使用一些內(nèi)存空間"。如果存在可用的空間,操作系統(tǒng)就會把它提供給該程序并且打上一個標(biāo)記以便不會再把這部分內(nèi)存分配給其它程序。
當(dāng)應(yīng)用程序使用完這部分內(nèi)存,它應(yīng)該被返回到OS;這樣以來,它就能夠被繼續(xù)分配給其它程序。如果該程序不返回這部分內(nèi)存,那么OS無法知道是否這塊內(nèi)存不再使用并進(jìn)而再分配給另一個進(jìn)程。如果一個內(nèi)存塊沒有釋放,并且所有者應(yīng)用程序丟失了它,那么,我們就說此應(yīng)用程序"存在漏洞",因為這部分內(nèi)存無法再為其它程序可用。
在一個典型的客戶端應(yīng)用程序中,較小的不太經(jīng)常的內(nèi)存泄漏有時能夠為OS所"容忍",因為在這個進(jìn)程稍后結(jié)束時該泄漏內(nèi)存會被隱式返回到OS。這并沒有什么,因為OS知道它把該內(nèi)存分配給了哪個程序,并且它能夠確信當(dāng)該程序終止時不再需要該內(nèi)存。
而對于長時間運(yùn)行的服務(wù)器守護(hù)程序,包括象Apache這樣的web服務(wù)器和擴(kuò)展php模塊來說,進(jìn)程往往被設(shè)計為相當(dāng)長時間一直運(yùn)行。因為OS不能清理內(nèi)存使用,所以,任何程序的泄漏-無論是多么小-都將導(dǎo)致重復(fù)操作并最終耗盡所有的系統(tǒng)資源。
現(xiàn)在,我們不妨考慮用戶空間內(nèi)的stristr()函數(shù);為了使用大小寫不敏感的搜索來查找一個字符串,它實際上創(chuàng)建了兩個串的各自的一個小型副本,然后執(zhí)行一個更傳統(tǒng)型的大小寫敏感的搜索來查找相對的偏移量。然而,在定位該字符串的偏移量之后,它不再使用這些小寫版本的字符串。如果它不釋放這些副本,那么,每一個使用stristr()的腳本在每次調(diào)用它時都將泄漏一些內(nèi)存。最后,web服務(wù)器進(jìn)程將擁有所有的系統(tǒng)內(nèi)存,但卻不能夠使用它。
你可以理直氣壯地說,理想的解決方案就是編寫良好、干凈的、一致的代碼。這當(dāng)然不錯;但是,在一個象PHP解釋器這樣的環(huán)境中,這種觀點僅對了一半。
三、 錯誤處理
為了實現(xiàn)"跳出"對用戶空間腳本及其依賴的擴(kuò)展函數(shù)的一個活動請求,需要使用一種方法來完全"跳出"一個活動請求。這是在Zend引擎內(nèi)實現(xiàn)的:在一個請求的開始設(shè)置一個"跳出"地址,然后在任何die()或exit()調(diào)用或在遇到任何關(guān)鍵錯誤(E_ERROR)時執(zhí)行一個longjmp()以跳轉(zhuǎn)到該"跳出"地址。
盡管這個"跳出"進(jìn)程能夠簡化程序執(zhí)行的流程,但是,在絕大多數(shù)情況下,這會意味著將會跳過資源清除代碼部分(例如free()調(diào)用)并最終導(dǎo)致出現(xiàn)內(nèi)存漏洞。現(xiàn)在,讓我們來考慮下面這個簡化版本的處理函數(shù)調(diào)用的引擎代碼:
代碼如下:
void call_function(const char *fname, int fname_len TSRMLS_DC){
zend_function *fe;
char *lcase_fname;
/* PHP函數(shù)名是大小寫不敏感的,
*為了簡化在函數(shù)表中對它們的定位,
*所有函數(shù)名都隱含地翻譯為小寫的
*/
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 **)
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的php的内存划分,解析PHP中的内存管理,PHP动态分配和释放内存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php json encode html
- 下一篇: php创建类用什么关键字,PHP面向对象