2

假設我想有兩個變量並且它們都等於null。 (更現實的說,我正在考慮一個包含大量null的數組,但是這個「兩個變量」場景足以解決這個問題。)顯然,我可以以多種方式做到這一點。我能做到這一點(方法1):PHP null和copy-on-write

$a = null; 
$b = $a; 

按照我的理解,這樣做的結果是,有一個zval的是由符號表兩個條目指出:'a''b'。但是,或者一個可能做到這一點(方法2):

$a = null; 
$b = null; 

天真人們會認爲這將導致兩個不同的變量容器,每個由符號表中的一個條目指向。

它與這一後續,如果你想有一個大陣,數組的許多元素會null,它的效率更高(在zval的/內存使用方面)來創建一個$master_null變量與值null ,然後通過使用$master_null來指定陣列的null元素?

+0

爲什麼不試試呢?看起來很簡單。 – Halcyon 2012-04-21 15:32:30

+0

@Frits:我不知道如何確定腳本中存在哪些zvals。 PHP在每種情況下的行爲都是相同的;隱藏的內部差異來自用戶。 – Hammerite 2012-04-21 15:53:30

+0

但有效的記憶屬性不會被隱藏起來。這是你想知道的嗎? – Halcyon 2012-04-21 16:04:11

回答

2

考慮這個腳本:

$arr = array(); 
for ($i = 0; $i < 100000; $i++) $arr[] = null; 
echo memory_get_usage() . "\n"; 

這在我的機器上輸出:21687696,也就是21 MB使用的內存。另一方面使用這個:

$master_null = null; 
$arr = array(); 
for ($i = 0; $i < 100000; $i++) $arr[] = $master_null; 
echo memory_get_usage() . "\n"; 

輸出:13686832,這是13 MB。根據這些信息,您可以假設您的內存使用情況值得關注,實際上使用「master null」變量實際上更好。但是,您仍然需要擁有數組中的所有項目,並且HashTable中的每個條目(數組的內部表示形式)都需要一些內存。

如果您想深入瞭解zvals和參考資料,我建議您使用功能debug_zval_dump。利用它,你可以看到,哪些變量共享相同的zval:

$a = $b = $c = $d = "abc"; 
debug_zval_dump($a); 
$x = $y = $z = $w = null; 
debug_zval_dump($x); 
$q = null; 
debug_zval_dump($q); 

,輸出:

string(3) "abc" refcount(5) 
NULL refcount(5) 
NULL refcount(2) 

這意味着,儘管變量$ x和$ q都是NULL,他們不是同樣的zval。但$ x和$ y共享相同的zval,因爲它們是相互分配的。我相信你知道功能debug_zval_dump,但如果不知道,請確保您仔細閱讀http://php.net/manual/en/function.debug-zval-dump.php的引用解釋。

同樣在我的文章結尾處,我想說這些信息可能對更好地瞭解PHP內部有用,我認爲做任何優化都是無用的。主要是因爲開始優化腳本的地方比這樣的微優化要好得多。此外,雖然這不是規範的一部分,但PHP作者可能會在將來更改此行爲(例如,所有NULL變量可能在未來版本中共享相同的zval)。

0

沒有一切能夠實現的是,您將有一個額外的變量$master_null。他們都指向一個空。讓他們指向$master_null是一回事。

+0

我不確定你是否瞭解我的問題的性質。 – Hammerite 2012-04-21 15:53:55

1

據我所知,PHP zval容器有一個引用計數邏輯。因此,我的印象是,如果你正在使用引用,即& $ master_null來初始化所有的NULL值,我認爲這可以節省你的空間,即所有的NULL數組指向與zval容器相同的引用。

下面是一個例子:每次使用時間

PHP is smart enough not to copy the actual variable container 
when it is not necessary. Variable containers get destroyed 
when the "refcount" reaches zero. The "refcount" gets decreased by 
one when any symbol linked to the variable container leaves the 
scope (e.g. when the function ends) or when unset() is called on a symbol. 

這樣:

# php -r '$var1 = NULL; $var2 = $var1; $var3 = $var1; debug_zval_dump(&$var1); debug_zval_dump(&$var2); debug_zval_dump(&$var3);' 
&NULL refcount(2) 
&NULL refcount(2) 
&NULL refcount(2) 

你可以閱讀更多關於PHP這裏的reference counting basis

東西值得從這個鏈接閱讀是& $ master_null,它的「refcount」會增加,當「refcount」達到零時,變量容器將從內存中移除。


從這裏上述評論的例子就是內存使用:

# php -r '$arr = array(); for ($i = 0; $i < 100000; $i++) $arr[] = null; echo memory_get_usage() . "\n";' 
11248372 
# php -r '$master_null = null; $arr = array(); for ($i = 0; $i < 100000; $i++) $arr[] = &$master_null; echo memory_get_usage() . "\n";' 
6848488 
# php -r '$master_null = null; $arr = array(); for ($i = 0; $i < 100000; $i++) $arr[] = $master_null; echo memory_get_usage() . "\n";' 
6848468