$a = 1; $b=$a; $a=2; 这段代码的内存是怎样分配的?

  1. 遇到一个面试题
    $a = 1; $b=$a; $a=2; 这段代码的内存是怎样分配的?
  2. 通过我在网上的查询得到两种不同的观点:

    1)一种是

     $a = 1;  首先给$a分配一个内存 地址一 并且它里面存的值是 1
     $b=$a;   将$a的变量容器复制一份,成为一个新的变量容器,$b指向这个容器(在这一步就进行了复制变量容器操作)
     $a=2;      这时改变$a的值变成2,就不会影响$b的值了

    2)另一种方案就是

     $a = 1;  首先给$a分配一个内存 地址一 并且它里面存的值是 1
     $b=$a;   将$b的也指向$a的地址一,此时不进行复制变量容器操作
     $a=2;     这时需要改变$a的值变成2,这时就需要复制$a 这个变量容器,让$b指向这个新的变量容器地址。
    
  3. 接下来就是我的验证方式了,
    第一种方式:我是从内存变化的角度来说明:

     echo 'PHP版本:'.PHP_VERSION."<br>";
     echo  '初始内存大小:'.memory_get_usage()."<br>";
     $a = 1;
     echo  '执行$a = 1后内存变成:'.memory_get_usage()."<br>";
     $b=$a;
     $a=2;
     echo  '执行$a=2后内存变成:'.memory_get_usage()."<br>";
     输出:
     
PHP版本:7.0.15
初始内存大小:6409416
执行$a = 1后内存变成:6409416
执行$a=2后内存变成:6409416

我发现内存竟然没有变化,验证失败了。

第二种验证方式:

我用的是php 的debug_zval_dump

我的环境是php7,但是这个函数似乎不支持int类型的数据,
我不得不重新弄一个类似的例子来验证:
     echo PHP_VERSION."<br>";
    $a = 'a';
    debug_zval_dump($a);
    echo "<br>";
    $b=$a;
    debug_zval_dump($a);
    echo "<br>";
    $a='a1';
    debug_zval_dump($a);
     输出:
     
     7.0.15
    string(1) "a" refcount(1) 
    string(1) "a" refcount(1) 
    string(2) "a1" refcount(1)
    
    这时问题就来了,为什么refcount值始终是1,难道执行完 $b=$a;不是应该    refcount的值加一吗
    我怀疑是我的php版本问题,我又去php7.1上执行
    输出:
    7.1.1
    <br>string(1) "a" refcount(1)
    <br>string(1) "a" refcount(1)
    <br>string(2) "a1" refcount(1)
    
    一样的结果。
    然后我就去看一下php文档,发现我中文档中的
        我也执行:
      echo 'PHP版本:'.PHP_VERSION."<br>";
    $var1 = 'Hello World';
    debug_zval_dump($var1);
    
    输出:
        PHP版本:7.0.15
        string(11) "Hello World" refcount(1)
    而文档的输出是 refcount值为2
  

文档链接

我的这一条验证之路也被堵死了,

请各位大神给我点指导意见,是在是弄不出来了。

阅读 4.5k
6 个回答

我上面举的例子里面传的参数就是字符串,
我刚把文档的例子拿到我本地运行了一下输出的和文档还是不一致:

    echo 'PHP版本:'.PHP_VERSION."<br>";
    $a = "new string";
    $b = $a;
    xdebug_debug_zval( 'a' );
    输出:
    PHP版本:7.0.15
    a:
    (refcount=0, is_ref=0)string 'new string' (length=10)
    
    

刚刚去查了一下这种情况在java上的实现的方式,感觉这个解释还是比较合理的。

$a =1;
首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有1这个值,如果没找到,就将1存放进来,然后将a指向1。
$b=$a;
着处理$b=$a;在创建完b的引用变量后,因为在栈中已经有1这个值,便将b直接指向1。这样,就出现了a与b同时均指向1的情况。
$a=2;
这时,如果再令a=2;那么编译器 会重新搜索栈中是否有2值,如果没有,则将2存放进来,并令a指向2;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这 种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

php7不再对简单值进行引用计数

这个问题就好比一群博士生讨论“水滴从高空落下砸在人身上会怎样一样”!各种牛逼套路,然后说不出个所以然!突然冒出一个学渣,问他们淋没淋过雨一样!

你们的方法都太牛逼了,都是大佬!我是真看不懂!

$a = 1;
$b = $a;
$a = 2;

echo $a;
echo $b;

如果$b输出1,那它必然是新开辟了一块内存,因为$a的值已经是2了,如果引用了$a的内存,那$b也应该输出2!

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题