PHP - 为什么按引用传递使用相同数量的内存?

PHP - why does passing by reference use the same amount of memory?

我的 PHP 脚本中得到 'memory exhausted'。我不知道为什么。限制为 128Mb。我从 javascript xmlrequest() 发送一个最大 10MB(通常小于 1MB)的 json 字符串。 PHP 脚本本身是 43K。即使将所有内容复制十几遍我也不应该 运行 内存不足。我在 getParentFolders() 对数据库进行了几次调用,但只产生了几行。当然不是它声称我正在使用的 62 兆字节。我使用过 Xdebug(见图),但这并没有告诉我任何有用的信息,只是,是的,我正在使用大量内存。

所以此时我正在尝试 'best practices' 以尽量减少内存使用。一个简单的修复,或者我认为,是通过引用传递值。所以我在每个函数的每个变量前都放了一个“&”。令我惊讶的是,内存消耗没有变化。事实上,它稍微差了几个字节。我也尝试过将每个变量用作全局变量,但再次令我惊讶的是,差别不大。

所以这是怎么回事?为什么通过引用传递和使用全局变量没有产生我预期的性能优势? (见图片)

Xdebug 'pass by value'

Xdebug 'pass by reference'

请注意它们几乎相同。

对于那些需要代码的人,这里是 getParentFolders() 函数,returns 只是一个短字符串,但不知何故使用了 70Mb!

function getParentFolders(&$node) {  //returns a string of folders
    debugprint("GetParentFOlders()");  //prints if $DEBUG flag is on
    $parent = getParent($node);
    $path = "";
    while ($parent) {  //goes till we hit root folder
        $path = $parent->title . '/' . $path;  //prepend it
        $parent = getParent($parent);
    }
    return $path;
}

function getParent(&$node) {  //return node that is the parent 
    global $email;
    $parentId = $node->parentId;
    $clientId = $node->parentClient;
    $idCol = $clientId . "_id";
    $tablename = $email . "_bookmarks";
    $query = "SELECT * FROM `$tablename`
                        WHERE $idCol = '$parentId'";  //only return one row since id is unique
    $result = sendquery($query);
    return (object) $result[0];
}

编辑:

澄清一下,我正在寻找 PHP 内存使用情况和最佳实践的技术解释 - 特别是为什么我没有看到内存差异 - 不是问题的解决方法。

使用LIMIT 1确保查询结果return在一行;如果没有找到结果,则使 getParent() return falsenull 以便可以将其设置为 $parent 以退出 while 循环。而且我认为您不需要在您的案例中通过引用传递 $node 参数。

$node的值是一个引用,即指向一个对象的指针。在 PHP 5+ 中, "objects" 不是直接的值。您总是通过指向对象的指针来处理对象:当您执行 new ClassName 时,它会计算为指向对象的指针;当您使用 -> 运算符时,它需要一个指向左侧对象的指针。

所以如果这两个函数都是按值传递的,那么传递的东西的大小就是指针的大小。当您通过引用传递时,这基本上将指针包装在另一个大小相同的指针级别(尽管总内存更大,因为有两个指针)。通过引用传递的唯一一点是它允许您在函数内部分配给 $node 以指向不同的对象或持有不同类型的值,并将其反映在调用函数中传递的变量中, 但你没有在这里的任何地方分配给 $node (修改指向 $node 的对象的字段与分配给 $node 不同),所以按引用传递是没有意义的这里。

(此外,即使您传递了一个值类型,如 PHP 中的数组,它们也具有写时复制语义,并且在您写入之前不会被复制。即使您写入它并导致它制作一个副本,该副本只会持续这个局部变量的生命周期,该局部变量在函数结束时结束,因此它不会创建持久内存使用。)

答案是对象不能按值传递。它们总是 通过引用传递。 'pass by reference' 运算符“&”除了将对象引用(即指针)包装在包装器中,然后传递新指针外,什么都不做。

至于内存使用,没有简单的答案,除了数据库查询结果似乎有很多开销,并且您想 'footprint'(即从数据库返回的任何结果,或任何变量)尽可能小。