2

Suppose I want to have two variables and have them both equal to null. (More realistically, I am thinking about an array that contains a large amount of nulls, but the "two variables" scenario is sufficient for the question.) Obviously, I can do this in more than one way. I can do this (method 1):

$a = null;
$b = $a;

By my understanding, the result of this is that there is one zval that is pointed to by two entries in the symbol table: 'a' and 'b'. But alternatively one might do this (method 2):

$a = null;
$b = null;

Naively one would expect that this should result in two different zvals, each pointed to by one entry in the symbol table.

Does it follow from this that if you want to have a large array, and many elements of the array will be null, it's more efficient (in terms of zval/memory use) to create a $master_null variable with the value null, and then write the null elements of the array by assigning using $master_null?

4

3 回答 3

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(数组的内部表示)中的每个条目也需要一些内存。

如果您想更深入地了解 zval 和引用,我建议使用函数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,因为它们是相互分配的。我相信你知道 function debug_zval_dump,但如果不知道,请务必仔细阅读http://php.net/manual/en/function.debug-zval-dump.php上的 refcount 说明。

同样在我的帖子的最后,我想说这些信息可能对更好地了解 PHP 内部结构很有用,我认为做任何优化都是无用的。主要是因为有比这种微优化更好的地方开始优化脚本。此外,虽然这不是规范的一部分,但 PHP 作者可能会在未来改变这种行为(例如,所有 NULL 变量可以在未来的某个版本中共享相同的 zval)。

于 2012-04-21T16:08:17.760 回答
1

据我了解,PHP zval 容器具有引用计数逻辑。因此,我的印象是,如果您使用引用即 &$master_null 来初始化所有 NULL 值,我认为这可以节省空间,即数组的所有 NULL 项都指向对 zval 容器的相同引用。

这是一个例子:

# 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引用计数基础的更多信息:

此链接中值得一读的内容是:

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.

因此,每次使用 &$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
于 2012-04-21T16:07:46.980 回答
0

没有所有可以实现的是你会有一个额外的变量,称为$master_null. 它们都指向一个空值。让他们每个人都指向$master_null是同一件事。

于 2012-04-21T15:33:42.660 回答