内存泄漏?!在“array_map”中使用“create_function”时,垃圾收集器是否正确?

2024-05-08

我在 StackOverflow 上找到了以下解决方案,从对象数组中获取特定对象属性的数组:PHP - 从对象数组中提取属性 https://stackoverflow.com/questions/1118994/php-extracting-a-property-from-an-array-of-objects/25807920#25807920

建议的解决方案是使用array_map并在其中创建一个函数create_function如下:

$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);

会发生什么?:array_map在本例中遍历每个数组元素stdClass目的。首先它创建一个像这样的函数:

function($o) {
    return $o->id;
}

其次,它为当前迭代中的对象调用此函数。它有效,它的工作原理几乎与这个类似的解决方案相同:

$catIds = array_map(function($o) { return $o->id; }, $objects);

但该解决方案仅在 PHP 版本 >= 5.3 中运行,因为它使用Closure概念=>http://php.net/manual/de/class.closure.php http://php.net/manual/de/class.closure.php

现在真正的问题是:

第一个解决方案是create_function增加内存,因为创建的函数将被写入内存并且不会被重用或销毁。在第二个解决方案中Closure它会。

因此,这些解决方案给出了相同的结果,但在内存方面具有不同的行为。

以下示例:

// following array is given
$objects = array (
    [0] => stdClass (
        [id] => 1
    ),
    [1] => stdClass (
        [id] => 2
    ),
    [2] => stdClass (
        [id] => 3
    )
)

BAD

while (true)
{
    $objects = array_map(create_function('$o', 'return $o->id;'), $objects);
    // result: array(1, 2, 3);

    echo memory_get_usage() ."\n";

    sleep(1);
}

4235616
4236600
4237560
4238520
...

GOOD

while (true)
{
    $objects = array_map(function($o) { return $o->id; }, $objects);
    // result: array(1, 2, 3);

    echo memory_get_usage() ."\n";

    sleep(1);
}

4235136
4235168
4235168
4235168
...

我花了很多时间来找出这个问题,现在我想知道,这是垃圾收集器的错误还是我犯了一个错误? 为什么将已经创建和调用的函数留在内存中是有意义的,因为它永远不会被重用?

这是一个运行示例:http://ideone.com/9a1D5g http://ideone.com/9a1D5g

Updated:当我递归搜索我的代码及其依赖项时,例如PEAR 和 Zend 然后我发现了这个BAD太频繁了。

Updated:当两个函数嵌套时,我们从内到外计算该表达式。换句话说,首先是开始create_function(一次)并且返回函数名称是单次调用的参数array_map。但是因为 GC 忘记将其从内存中删除(没有指向内存中函数的指针)并且 PHP 无法重用已经位于内存中的函数,让我认为存在错误,而不仅仅是“性能不佳”的情况。这行特定的代码是 PHPDoc 中的一个示例,并在许多大型框架中重用,例如Zend 和 PEAR 等等。再多一行,您就可以解决这个“错误”,检查一下。但我并不是在寻找解决方案:我是在寻找真相。这是一个错误还是这只是我的方法。而后者我还无法决定。


如果是create_function()lambda 风格的函数是使用以下命令创建的eval(),并返回包含其名称的字符串。然后该名称作为参数传递给array_map()功能。

这与闭包式匿名函数不同,闭包式匿名函数根本不使用包含名称的字符串。function($o) { return $o->id; } IS函数,或者更确切地说是 Closure 类的实例。

The eval()功能,内部create_function(),执行一段创建所需函数的 PHP 代码。有点像这样:

function create_function($arguments,$code) 
{
  $name = <_lambda_>; // just a unique string
  eval('function '.$name.'($arguments){$code}');
  return $name;
}

请注意,这是一种简化。

因此,函数一旦创建,它将一直持续到脚本结束,就像脚本中的普通函数一样。在上面的 BAD 示例中,循环的每次迭代都会创建一个新函数,占用越来越多的内存。

但是,您可以故意破坏 lambda 样式的函数。这很简单,只需将循环更改为:

while (true)
{
    $func = create_function('$o', 'return $o->id;');
    $objects = array_map($func, $objects);
    echo memory_get_usage() ."\n";
    sleep(1);
}

包含函数引用(= 名称)的字符串在此处已明确且可访问。现在,每一次create_function()被调用时,旧函数会被新函数覆盖。

所以,不,不存在“内存泄漏”,它就是这样工作的。

当然,下面的代码效率更高:

$func = create_function('$o', 'return $o->id;');

while (true)
{
    $objects = array_map($func, $objects);
    echo memory_get_usage() ."\n";
    sleep(1);
}

并且仅应在您的 PHP 版本不支持闭包样式匿名函数时使用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

内存泄漏?!在“array_map”中使用“create_function”时,垃圾收集器是否正确? 的相关文章

  • 检查 $_POST 数据

    我正在对表单进行一些垃圾邮件检查 下面的代码在我的本地主机上正常工作 如果为 true 则重定向到 google com 但是 当它在生产服务器上时却不起作用 执行脚本的其余部分并且不重定向到 Google com if POST SERV
  • 免费 PHP 登录库 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • NodeJS:调用 global.gc() 不会将内存减少到最低限度?

    为了调查内存泄漏 我设置了一条触发的路线global gc 在每个POST gc app post gc function req res global gc 但是 我注意到 如果我发送垃圾邮件此请求 每次都会越来越多地减少内存使用量 不应
  • setcookie with expire=0 浏览器关闭后不会过期

    我使用setcookie来制作一个过期 0的cookie 从 PHP 文档来看 link http php net manual en function setcookie php cookie 过期的时间 这是一个 Unix 时间戳 所以
  • 图像随机损坏(但刷新后加载)并显示“资源解释为图像但使用 MIME 类型 text/html 传输”

    我目前正在开发一个简单的 php 网站 问题是 我的整个网站中的图像 发生在所有 php 文件中 随机损坏并显示错误资源解释为图像 但以 MIME 类型 text html 传输但是 如果我尝试多次刷新页面 可以再次加载图像并且错误消失 我
  • Ninject 垃圾收集 [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我在一个由
  • 无法访问 localhost/xampp/index.php

    我刚刚安装了 Windows 7 的 XAMPP 控制面板似乎工作正常 我启动了 MySql 和 Apache 我遇到的问题是 当我在浏览器 Google Chrome 中输入 localhost 时 它会将我发送到 http localh
  • Yii2 - 错误请求 (#400) |前端和后端cookie

    仅当我打开时才会出现此问题frontend and backend在相同的browser 设想 与后端交互 gt 切换选项卡 gt 与前端交互 gt 切换选项卡返回 gt 与后端交互 gt 错误请求 400 Cookie 后端 identi
  • PHP:读取所有传入 HTTP 请求的类 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在 JavaScript 中创建服务器端进度指示器?

    我想在我的网站中创建一个部分 用户可以在其中进行一些简单的操作update纽扣 这些中的每一个update按钮将发送到服务器 并在幕后进行长时间的处理 当服务器处理数据时 我希望用户有某种进度指示器 例如进度条或文本百分比 我使用 jQue
  • 将 cookie 设置为在当天结束时过期

    我想设置一个 cookie 并让它在一天结束时过期 这有效 但 24 小时后过期 setcookie route upgrade voted true time 86400 这不起作用 setcookie route upgrade vot
  • docker 中的 php Curl 冲突 CURLOPT_FILE 和 CURLOPT_RETURNTRANSFER

    当我使用curl时CURLOPT FILE and CURLOPT RETURNTRANSFER选项 文件为空 没有任何curl错误 fp fopen saveTo w ch curl init fileUrl curl setopt ch
  • Facebook PHP-SDK 页面刷新后似乎丢失了 userID

    我似乎登录工作正常 我可以登录 接受应用程序 第一次 然后显示用户信息 例如姓名 图片 等 然而 当我刷新页面时 userid 又回到 0 我必须再次登录 我不确定问题是什么 我必须在每次页面加载时重新启动它还是什么 我不知道 我会发布一些
  • PHP 编码风格回归;在开关/外壳中

    我们正在尝试为我们的团队实施新的编码风格指南 当未找到 break 时 php codeniffer 会在 switch case 语句上打印警告 如下所示 switch foo case 1 return 1 case 2 return
  • CodeIgniter:My_Lang 中的 get_instance

    我发现这个有用的国际化代码 http pastebin com SyKmPYTX http pastebin com SyKmPYTX 一切正常 除了我无法在此类中使用 CI 函数 我想从 DB 设置 languages 和 special
  • PHP 中的 -> 和 :: 有什么区别?

    这个东西困扰我好久了 一直找不到 在 php 中使用 和 gt 之间的类有什么区别 让我举个例子 想象一个名为 MyClass 的类 该类中有一个函数 myFunction 使用有什么区别 MyClass myclass new MyCla
  • session_start():无法解码会话对象

    我有时在使用 CodeIgniter 时遇到以下问题 错误 2019 03 05 19 57 26 gt 严重性 警告 gt session start 无法解码会话对象 会话已被销毁 system libraries Session Se
  • 使用会话 php 创建 cookie?

    我使用会话来登录我网站中的用户 问题是 我想让用户remember密码 因此关闭 打开浏览器后他们不需要再次登录 我需要使用 cookie 和 session 来实现它吗 my code user POST user pass POST p
  • PHP 拒绝从 var_dump、print 等输出数据

    我目前正在运行 WAMP 服务器 并且在过去的 30 分钟内一直在尝试弄清楚我的项目如何以及为什么不会输出任何指定的 PHP 数据 起初我以为是因为我有一个 htaccess文件的output buffering被禁用 所以我删除了它 仍然
  • 使用 Vue 的多模式组件

    我在 Vue 中实现动态模式组件时遇到问题 A common approach I follow to display a set of data fetched from the db is I dump each of the rows

随机推荐