-->

PHP空和写入时复制(PHP null and copy-on-write)

2019-09-16 16:38发布

假设我想有两个变量,让他们都等于null 。 (更为现实的,我想是含有大量的阵列null S,但“两个变量”的情况就足够了问题。)很显然,我可以在一个以上的方式做到这一点。 我能做到这一点(方法1):

$a = null;
$b = $a;

按照我的理解,这样做的结果是,有一个zval的是由符号表两个条目指出: 'a''b' 。 但是,或者一个可能做到这一点(方法2):

$a = null;
$b = null;

天真的人会想到,这将导致两个不同的变量容器,每个由符号表中的一个条目指向。

它与这个,如果你想有一个大阵,数组的许多元素会跟着null ,它的效率更高(在zval的/内存使用方面)来创建一个$master_null与变量的值null ,然后写null使用分配数组的元素$master_null

Answer 1:

考虑一下这个脚本:

$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。 基于这些信息,你可以假设,在尽可能内存占用你的关心,它实际上是更好的使用确实“主空”变量。 但是你仍然需要有阵列中所有在哈希表中的每个条目(数组的内部表示)的项目,同时也需要一些内存。

如果你想在变量容器和引用深入挖掘,我建议使用功能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)。



Answer 2:

从我个人理解,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时间,这是“引用计数”增加,当“引用计数”达到零,变量容器从内存中删除。


从上面的例子评论这里是内存使用:

# 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


Answer 3:

没有所有将实现的是,你会叫一个额外的变量$master_null 。 他们都指向一个空。 让他们每个点$master_null是同样的事情。



文章来源: PHP null and copy-on-write