導航:首頁 > 編程語言 > php回收內存

php回收內存

發布時間:2022-07-30 05:50:46

php程序里如何釋放內存

這個,不是PHP本身的問題。
而是你的伺服器網路帶寬的問題。
你用curl請求的是遠程的伺服器,要佔用帶寬吧?用戶訪問你的網站,也要佔用帶寬吧?於是,你的帶寬就悲劇了。
----------------------------------
一個PHP程序執行完,所有的東西就消失了,內存就自動釋放了...所以這方面你不需要考慮的。

② PHP主要是用來做什麼呢,和JAVA有什麼區別是

PHP主要使用來做網站以及Web應用開發的。跟JAVA區別如下:

一、語言優勢不同

1、PHP:即「超文本預處理器」,是一種通用開源腳本語言。在伺服器端執行的腳本語言。

2、JAVA:是一門面向對象編程語言,不僅吸收了C++語言的各種優點,還摒棄了C++里難以理解的多繼承、指針等概念。


二、語法不同

1、PHP:語法混合了C、Java、Perl以及 PHP 自創的語法。

2、JAVA:作為靜態面向對象編程語言的代表,極好地實現了面向對象理論,允許程序員以優雅的思維方式進行復雜的編程。

三、特點不同

1、PHP:利於學習,使用廣泛,主要適用於Web開發領域。

2、JAVA:具有簡單性、面向對象、分布式、健壯性、安全性、平台獨立與可移植性、多線程、動態性等特點。


③ PHP中對象的實例什麼時候消失回收

php作為腳本語言是頁面結束即釋放變數所佔內存的.

當一個 PHP線程結束時,當前佔用的所有內存空間都會被銷毀,當前程序中所有對象同時被銷毀。
GC進程一般都跟著每起一個SESSION而開始運行的.gc目的是為了在session文件過期以後自動銷毀刪除這些文件.
在PHP中,沒有任何變數指向這個對象時,這個對象就成為垃圾。PHP會將其在內存中銷毀;這是PHP 的GC垃圾處理機制,防止內存溢出。類似與C++中的智能指針一樣。
執行這些函數也可以起到回收作用 __destruct /unset/mysql_close /fclose
php對session有明確的gc處理時間設定 session.gc_maxlifetime 如果說有垃圾,那就是整體的程序在框架使用中,會多次調用同一文件等等造成的非單件模式等。

析構函數:當某個對象成為垃圾或者當對象被顯式銷毀時執行。

④ php內存消耗制度是怎樣的,如何能優化內存呢

如果兩個對象之間存在著相互引用的關系,如「父對象-子對象」,對父對象調用 unset() 不會釋放在子 對象中引用父對象的內存(即便父對象被垃圾回收,也不行) 這種情況如果在你的一個長期運行的代碼中使用到了一大堆相互引用的對象,尤其是在對象相對較大的情況下,內存會迅速地消耗殆盡。 還有注意的是在定義類的時候,一定要定義銷毀類的方法: __destruct(),該方法可將所有內部的父對象引用全部清除,以避免上面的那種特殊情況。

⑤ PHP命令執行PHP腳本,結束之前,內存會回收嗎


再詳細說下問題:
unix下,用php命令來執行php腳本,在php結束之前,內存有沒有機會被回收?新的GC演算法有沒有機會被調用?
出現這個問題,是因為線上有個離線數據導入腳本,需要把幾千萬行數據篩選入庫,發現,在執行過程中,到達一定程度,就會拋出內存使用超過最大值。
1Fatalerror:
那第一想到的就是程序是不是有什麼bug,造成內存超出,看了半天沒有發現問題,於是,突然出現了這個疑問。那要解決這個疑問,最好的辦法就去翻源碼吧。
在之前我這么說:
都知道,PHP5.3有了新的垃圾回收機制:GC,它不是重點,不談它的原理。
經過翻閱PHP源碼,發現,調用這個的時機是在main/main.c::php_request_shutdown這個函數中,
12/*7.Shutdownscanner/executor/compilerandrestoreinientries*/zend_deactivate(TSRMLS_C);
php_request_shutdown,通過名字就能看出,它是在php請求結束的時候執行的,在這里會執行gc_collect_cycles來清理內存。

其實這句話是沒錯,但它只針對於SAPI介面(之前我就錯在這個地方。),在用PHP命令執行php腳本的時候,是不會執行這個php_request_shutdown的。
那回到最初的問題,過程中到底有沒有執行GC呢?
為了更直觀有效的知道答案,我選擇了最BT,最暴力的方法,攔截gc_collect_cycles,輸出error_log到文件,只要執行了,
那肯定會輸出log來。
重新編譯PHP後,果不其然,符合官方的說法,只要buckets滿超過默認值1000,就會啟動GC來清理沒用的內存,防止內存泄露。
那問「什麼時間觸發的GC呢?」,答「buckets超過1000的時候啊」,這不屁話嘛,要的是真真正正的執行流程,so。。不斷的debug,
不斷的grep,不斷的step,不斷的C+T,終於搞清楚了。下面就來根據官方的說法詳細談談,PHP到底是怎麼觸發的。
有一點要注意,PHP的命令入口和sapi介面的入口是不同的,我就載在這個地方,以為都公用一個。
測試代碼以官方文檔為例:
1234567891011121314<?phpclassFoo{public$var='3.1415962654';}for($i=0;$i<=1000000;$i++){$a=newFoo;$a->self=$a;}echomemory_get_peak_usage()," ";?>
這樣的代碼,在PHP5.3之前,肯定會造成大量的內存泄露,不過,誰在開發時又能開發出這么變態的代碼來?除非這個人很變態。^.*
那PHP的命令入口是什麼?流程又是什麼?
主要函數流程如下:
入口main函數(sapi/cli/php_cli.c)==》php_execute_script(main/main.c)==>zend_execute_scripts(Zend/zend.c)==>execute(Zend/zend_vm_execute.h)
調用GC的地方在execute里。
簡單描述下這個過程,
main是入口,它的作用是根據我們傳遞的參數做不同的設置,最後會把我們的php腳本作為一個zend_file_handle指針傳遞給
php_execute_script函數,zend_file_handle其實就是把FILE*做了一下封裝,保存了一些其他的文件信息。
php_execute_script會做一些文件檢查工作,把php腳本加到哈希表included_files中。
php_execute_scripts會執行zend_compile_file函數來解釋我們寫的PHP代碼,最後執行execute。
應該都知道Zend把腳本解析完會生成op代碼保存到哈希表:active_op_array中,execute會逐個執行每個op,
op基本上都對應一個ZEND_ASSIGN_*_HANDLER這樣的一個宏,它就保存在active_op_array->opline->handlers中。
在進入到execute之後:
首先初始化execute_data,它保存了很多重要信息,上下文信息,然後調用ZEND_VM_SET_OPCODE宏,
把execute_data->opline的指針指向active_op_array->opline->handlers。
之後,execute會執行一個while循環,逐條執行opline:
(1){intret;#ifdefZEND_WIN32if(EG(timed_out)){zend_timeout(0);}#endifif((ret=EX(opline)->handler(execute_dataTSRMLS_CC))>0){switch(ret){case1:EG(in_execution)=original_in_execution;return;case2:op_array=EG(active_op_array);gotozend_vm_enter;case3:execute_data=EG(current_execute_data);default:break;}}}
每個handlers都會執行一個宏:ZEND_VM_NEXT_OPCODE(),它意思就是跳到下一個Opline,這樣就能逐條執行了。
最後跟蹤上面的PHP代碼會執行ZEND_ASSIGN_SPEC_CV_VAR_HANDLER這個宏,它是幹嘛的?他就是變數賦值
下面代碼執行的操作:
1234classA{}$a=newA();
這里就會執行這個宏。
在這個宏里有段代碼:
_FASTCALLZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS){zend_op*opline=EX(opline);zend_free_opfree_op2;zval*value=_get_zval_ptr_var(&opline->op2,EX(Ts),&free_op2TSRMLS_CC);zval**variable_ptr_ptr=_get_zval_ptr_ptr_cv(&opline->op1,EX(Ts),BP_VAR_WTSRMLS_CC);if(IS_CV==IS_VAR&&!variable_ptr_ptr){if(zend_assign_to_string_offset(&EX_T(opline->op1.u.var),value,IS_VARTSRMLS_CC)){if(!RETURN_VALUE_UNUSED(&opline->result)){EX_T(opline->result.u.var).var.ptr_ptr=&EX_T(opline->result.u.var).var.ptr;ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);ZVAL_STRINGL(EX_T(opline->result.u.var).var.ptr,Z_STRVAL_P(EX_T(opline->op1.u.var).str_offset.str)+EX_T(opline->op1.u.var).str_offset.offset,1,1);}}elseif(!RETURN_VALUE_UNUSED(&opline->result)){AI_SET_PTR(EX_T(opline->result.u.var).var,EG(uninitialized_zval_ptr));PZVAL_LOCK(EG(uninitialized_zval_ptr));}}else{value=zend_assign_to_variable(variable_ptr_ptr,value,0TSRMLS_CC);if(!RETURN_VALUE_UNUSED(&opline->result)){AI_SET_PTR(EX_T(opline->result.u.var).var,value);PZVAL_LOCK(value);}}/*zend_assign_to_variable()alwaystakescareofop2,neverfreeit!*/if(free_op2.var){zval_ptr_dtor(&free_op2.var);};ZEND_VM_NEXT_OPCODE();}
free_op2.var保存的是newA的對象.
free_op2.var這個是哪兒來的呢?
在整個execute期間,維持一個execute_data結構,裡面有個Ts指針
1union_temp_variable*Ts;
它用來保存一些臨時的變數信息,比如newA(),這個會保存到Ts鏈表裡,
opline->op2.u.var這個裡面保存了此臨時變數所在的位置,然後Ts+這個值是一個zval*指針,它就保存了newA產生的對象.
在代碼中
1if(free_op2.var){zval_ptr_dtor(&free_op2.var);};
zval_ptr_dtor會根據free_op2.var的值執行到Zend/zend_execute_API.c::_zval_ptr_dtor函數中,
_APIvoid_zval_ptr_dtor(zval**zval_ptrZEND_FILE_LINE_DC)/*{{{*/{zval*zv=*zval_ptr;#ifDEBUG_ZEND>=2printf("Recingrefcountfor%x(%x):%d->%d ",*zval_ptr,zval_ptr,Z_REFCOUNT_PP(zval_ptr),Z_REFCOUNT_PP(zval_ptr)-1);#endifZ_DELREF_P(zv);if(Z_REFCOUNT_P(zv)==0){TSRMLS_FETCH();if(zv!=&EG(uninitialized_zval)){GC_REMOVE_ZVAL_FROM_BUFFER(zv);zval_dtor(zv);efree_rel(zv);}}else{TSRMLS_FETCH();if(Z_REFCOUNT_P(zv)==1){Z_UNSET_ISREF_P(zv);}GC_ZVAL_CHECK_POSSIBLE_ROOT(zv);}}
GC_ZVAL_CHECK_POSSIBLE_ROOT(zv);
它就是最終GC演算法執行的地方.
gc_collect_cycles就在這個宏中執行了..
所以..
回到上面的問題,
php無論在SAPI介面或命令端,都會執行GC演算法來進行垃圾內存回收.

⑥ php如何釋放file函數的內存

file函數一般只佔用系統
句柄
資源。讀取其中的內容並保存至某個變數會佔用內存,跟file函數無關。
file函數在打開之後,需要用close關閉並釋放file句柄,否則可能會導致其他程序不能打開這個文件(文件鎖定)。
除了用alloc等函數顯式分配內存的外,一般不需要專門
釋放內存
,系統會在結束時自動回收內存。

⑦ php 在類中如何釋放內存。

unset()是可以釋放內存的,但是$str=null基本釋放不了的,建議還是用unset()就好了,$str=null只是用來清空變數,以防下面再用的時候遭到干擾的。

⑧ 有人研究過php的內存回收機制嗎

你是大牛,都研究源碼了。
俺只知道php是會自動釋放內存的,當php執行完成後,自動釋放改次請求的所有內存。
php.ini裡面的設置是單次請求最大允許的內存分配,如果本次請求內存超過配置,那麼對不起,php會因為內存無法分配導致程序崩潰而結束請求。

⑨ 求助!求助!PHP求助!ignore_user_abort(),set_time_limit(0),定時、持續運行

很無聊的寫法,你這樣遲早會溢出的。
如果是linux環境的話 用crontab計劃任務幾句搞定了。windows也有計劃任務啊。

實在不行要用你列出的這方法 就用跳轉啊 比如每十分鍾執行就跳轉,
設置個get把時間作為參數帶上就OK。

⑩ 簡單說明PHP的垃圾收集機制是怎樣的

PHP的基本GC概念
PHP語言同其他語言一樣,具有垃圾回收機制。那麼今天我們要為大家講解的內容就是關於PHP垃圾回收機制的相關問題。希望對大家有所幫助。PHP
strtotime應用經驗之談PHP memory_get_usage()管理內存PHP unset全局變數運用問題詳解PHP
unset()函數銷毀變數教你快速實現PHP全站許可權驗證一、PHP 垃圾回收機制(Garbage Collector 簡稱GC)
在PHP中,沒有任何變數指向這個對象時,這個對象就成為垃圾。PHP會將其在內存中銷毀;這是PHP的GC垃圾處理機制,防止內存溢出。當一個PHP線程結束時,當前佔用的所有內存空間都會被銷毀,當前程序中所有對象同時被銷毀。GC進程一般都跟著每起一個SESSION而開始運行的.gc目的是為了在session文件過期以後自動銷毀刪除這些文件.二、__destruct
/unset __destruct() 析構函數,是在垃圾對象被回收時執行。
unset 銷毀的是指向對象的變數,而不是這個對象。三、 Session
與PHP垃圾回收機制由於PHP的工作機制,它並沒有一個daemon線程來定期的掃描Session信息並判斷其是否失效,當一個有效的請求發生時,PHP
會根據全局變數 session.gc_probability和session.gc_divisor的值,來決定是否啟用一個GC,
在默認情況下,session.gc_probability=1, session.gc_divisor
=100也就是說有1%的可能性啟動GC(也就是說100個請求中只有一個gc會伴隨100個中的某個請求而啟動).PHP垃圾回收機制的工作就是掃描所有的Session信息,用當前時間減去session最後修改的時間,同session.gc_maxlifetime參數進行比較,如果生存時間超過gc_maxlifetime(默認24分鍾),就將該session刪除。
但是,如果你Web伺服器有多個站點,多個站點時,GC處理session可能會出現意想不到的結果,原因就是:GC在工作時,並不會區分不同站點的session.那麼這個時候怎麼解決呢?
1. 修改session.save_path,或使用session_save_path()讓每個站點的session保存到一個專用目錄,
2. 提供GC的啟動率,自然,PHP垃圾回收機制的啟動率提高,系統的性能也會相應減低,不推薦。
3. 在代碼中判斷當前session的生存時間,利用session_destroy()刪除。

引用計數基本知識
每個php變數存在一個叫做"zval"的變數容器中.一個zval變數容器,除了包含變數的類型和值,還包括兩個位元組的額外信息.第一個是"is_ref",是個bool值,用來標識這個變數是否是屬於引用集合(reference

set).通過這個位元組,php引擎才能把普通變數和引用變數區分開.由於php允許用戶通過使用&來使用自定義引用,zval變數容器中還有一個內部引用計數機制,來優化內存使用.第二個額外位元組是"refcount",用來表示指向這個zval變數容器的變數(也稱符號即symbol)個數.
當一個變數被賦常量值時,就會生成一個zval變數容器,如下例所示:

?

1
2
3
4

<?php
$a = "new string";

?>

在上例中,新的變數是a,是在當前作用域中生成的.並且生成了類型為string和值為"new
string"的變數容器.在額外的兩個位元組信息中,"is_ref"被默認設置為false,因為沒有任何自定義的引用生成."refcount"被設定為1,因為這里只有一個變數使用這個變數容器.調用xdebug查看一下變數內容:

?

1
2
3
4
5

<?php
$a = "new string";

xdebug_debug_zval('a');
?>

以上代碼會輸出:

?

1

a: (refcount=1, is_ref=0)='new string'

對變數a增加一個引用計數

?

1
2
3
4
5
6

<?php
$a = "new string";

$b = $a;
xdebug_debug_zval('a');
?>

以上代碼會輸出:

?

1

a: (refcount=2, is_ref=0)='new string'

這時,引用次數是2,因為同一變數容器被變數a和變數b關聯.當沒必要時,php不會去復制已生成的變數容器.變數容器在"refcount"變成0時就被銷毀.當任何關聯到某個變數容易的變數離開它的作用域(比如:函數執行結束),或者對變數調用了unset()函數,"refcount"就會減1,下面例子就能說明:

?

1
2
3
4
5
6
7

<?php
$a = "new string";
$b = $c = $a;
xdebug_debug_zval('a');
unset($b, $c);
xdebug_debug_zval('a');
?>

以上代碼會輸出:

?

1

a: (refcount=3, is_ref=0)='new string' a: (refcount=1, is_ref=0)='new string'

如果我們現在執行unset($a),$包含的類型和值的這個容器就會從內存刪除
復合類型(compound types)
當考慮像array和object這樣的復合類型時,事情會稍微有些復雜.與標量(scalar)類型的值不同,array和object類型的變數把它們的成員或屬性存在自己的符號表中.這意味著下面的例子將生成三個zval變數容器

?

1
2
3
4
5

<?php
$a = array('meaning' => 'life', 'number' => 42);

xdebug_debug_zval('a');
?>

以上代碼輸出:

?

1

a: (refcount=1, is_ref=0)=array ('meaning' => (refcount=1, is_ref=0)='life', 'number' => (refcount=1, is_ref=0)=42)

這三個zval變數容器是:a,meaning,number.增加和減少refcount的規則和上面提到的一樣

特例,添加數組本身作為數組元素時:

?

1
2
3
4
5
6
7

<?php
$a = array('one');

$a[] = &$a;

xdebug_debug_zval('a');
?>

以上代碼輸出的結果:

?

1

a: (refcount=2, is_ref=1)=array (0 => (refcount=1, is_ref=0)='one', 1 => (refcount=2, is_ref=1)=...)

可以看到數組a和數組本身元素a[1]指向的變數容器refcount為2
當對數組$a調用unset函數時,$a的refcount變為1,發生了內存泄漏
清理變數容器的問題
盡管不再有某個作用域中的任何符號指向這個結構(就是變數容器),由於數組元素"1"仍然指向數組本身,所以這個容器不能被消除.因為沒有另外的符號指向它,用戶沒有辦法清除這個結構,結果就會導致內存泄漏.慶幸的是,php將在請求結束時清除這個數據結構,但是php清除前,將耗費不少內存空間

回收周期
5.3.0PHP使用了新的同步周期回收演算法,來處理上面所說的內存泄漏問題
首先,我們先要建立一些基本規則:
如果一個引用計數增加,它將繼續被使用,當然就不再垃圾中.如果引用技術減少到零,所在的變數容器將被清除(free).就是說,僅僅在引用計數減少到非零值時,才會產生垃圾周期(grabage
cycle).其次,在一個垃圾周期中,通過檢查引用計數是否減1,並且檢查哪些變數容器的引用次數是零,來發現哪部分是垃圾

為避免不得不檢查所有引用計數可能減少的垃圾周期,這個演算法把所有可能根(possible roots
都是zval變數容器),放在根緩沖區(root buffer)中(用紫色標記),這樣可以同時確保每個可能的垃圾根(possible
garbage root)在緩沖區只出現一次.僅僅在根緩沖區滿了時,才對緩沖區內部所有不同的變數容器執行垃圾回收操作。
腳本之家查來的

閱讀全文

與php回收內存相關的資料

熱點內容
如何上網上設個人加密賬戶 瀏覽:44
linux打開ssh服務 瀏覽:78
微信位置可以加密嗎 瀏覽:470
演算法蠻力法 瀏覽:438
隨機排練命令 瀏覽:147
python多進程並發 瀏覽:41
安卓軟體安裝如何躲避安全檢測 瀏覽:647
奇幻潮翡翠台源碼百度雲盤 瀏覽:187
什麼軟體可以免費pdf轉word 瀏覽:15
php正則表達式大全 瀏覽:394
androidntp時間 瀏覽:299
輪機長命令簿英文 瀏覽:148
oppo鈴聲設置被加密怎麼處理 瀏覽:548
粵苗app圖形驗證碼怎麼填 瀏覽:899
管家婆架設雲伺服器 瀏覽:254
php的登錄界面代碼 瀏覽:997
php開發客戶端 瀏覽:998
theisle測試服怎麼搜伺服器 瀏覽:447
廣播PDF 瀏覽:218
單片機編程300例匯編百度 瀏覽:35