内存泄漏?!在“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”时,垃圾收集器是否正确? 的相关文章

  • 使用多个 WHERE 子句更新 Codeigniter 中的批次

    我查看了 CI 用户指南来了解如何处理update batch 并且它似乎只接受一个索引来匹配要更新的行 但在我的例子中 我需要指定两个索引 例如lang and id page我一起用作索引 这样的lang en id page 115是
  • Laravel 4.2 Composer 安装错误:“无法扫描类”

    我想通过 Composer 在新的 Laravel 4 2 安装上安装一些软件包 但是 我遇到了例外 这是我的作曲家文件 name laravel laravel description The Laravel Framework keyw
  • 当php脚本通过ajax运行时显示进度条

    我有一个通过 ajax 向服务器提交值的表单
  • 为什么 0.5 mod 0.1 在不同的编程语言中结果不同?

    我有一个关于模数的问题 模运算求一个数除以另一个数的余数 我原本期望 0 5 0 1 0 的结果 但是当我在 PHP 或 net 中运行它时 我得到 0 1 我运行的 php 代码是 var dump fmod 0 5 0 1 在 net中
  • 如何缩短 PHP if 语句?

    我有一个 if 语句 我需要将单个字符串与许多不同的选项进行比较 我在下面发布的代码非常清楚地表明了我的意思 我知道有两种方法可以做到这一点 但另一种甚至更长 那么 是否有任何函数可以以更短的方式实现类似的功能 我的要求可能看起来很愚蠢 但
  • PHP 如何查找自日期时间以来经过的时间? [复制]

    这个问题在这里已经有答案了 如何查找自日期时间戳记以来经过的时间2010 04 28 17 25 43 最终输出文本应该是这样的xx Minutes Ago xx Days Ago 大多数答案似乎都集中在将日期从字符串转换为时间 您似乎主要
  • Facebook Graph API - 如何用新行发布到墙上?

    我正在使用 Facebook Graph API 但遇到一个问题 我找不到任何方法如何使用一些 HTML 代码发布到墙上or新线路 怎么办呢 这是我的代码
  • 如何使用 PHP 从 MSSQL 读取图像字段

    我正在创建一个网站 需要同步从离线 MSSQL 服务器读取的在线 MySQL 数据库 除图像字段外 所有通信和从 MSSQL 读取所有字段均工作正常 我已经使用 PHP 和 Mysql 一段时间了 知道如何向 MySQL 数据库插入 检索图
  • Pear PHP UML 类图 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在尝试创建现有代码的图形表示 我尝试使用 VS PHP 使用 Visual Studios 201
  • 在 PHP 中比较字符串的方式与 MySQL 相同

    我将 varchar 存储在 utf8 MySQL 表中并使用 utf8 general ci 排序规则 我在 varchar 上有一个唯一索引 我想在 PHP 中进行字符串比较 这相当于 MySQL 对索引所做的操作 一个具体的例子是 我
  • 访问父函数中定义的变量

    有没有办法访问 foo从内部inner function outer foo function inner print foo inner outer PHP 在 PHP 5 3 中 你可以这样做 function outer foo in
  • 使用 PHP 和 MySQL 的服务器端事件

    我正在使用 PHP 和 MySQL 构建一个 非常基本的 应用程序 该应用程序的目的是在网页上显示 实时 数据交易 这些交易来自于transactionsMySQL 数据库中的表 到目前为止 我可以在网页上检索并显示数据 不过我期待看到数据
  • PHP:我是否将事件驱动编程与信号感知接口(信号和槽/观察者模式)混淆了?

    我看到很多人说 Symfony2 Zend Framework 2 等都是事件驱动的 在桌面世界中 通过事件驱动编程 我了解到应用程序每当其状态发生变化时都会通知其观察者 由于 PHP 应用程序是无状态的 因此无法执行此类操作 IE 让观察
  • openssl_decrypt 标签值

    我在网站中使用 openssl encrypt decrypt 方法 但在使用 tag 选项时遇到了一些问题 openssl encrypt data method key options iv tag openssl decrypt da
  • 刷新页面后保留输入值

    我有一个带有输入字段的表单 该输入包含一个下拉菜单 从数据库中读取信息 如果用户输入值 并且当他到达下拉菜单时 他没有找到他想要的内容 他会转到另一个页面将此信息添加到下拉菜单 然后转到第一页继续输入信息 如果他转到另一个页面向下拉菜单添加
  • 从 XML 获取 viewCount [重复]

    这个问题在这里已经有答案了 我目前正在使用YouTube API https developers google com youtube 来自 Google 我正在尝试获取 viewCount 数组 我已经尝试过这个 但一点运气都没有 He
  • XAMPP 不解析 PHP

    我刚刚安装了 XAMPP 1 8 1 并重新启动了计算机 开始运行 Apache 和 MySQL 并在 XAMPP 下的 htdocs 目录中的测试文件夹中创建了一个测试文件 当我访问 xampp index php 时 他们的页面显示正常
  • 语言翻译语法

    我正在尝试为我的项目添加另一种语言 我们知道语言可以表现出主语和谓语的差异 例如 英语 Mustafa和他的朋友去看电影ahmet today 土耳其 Mustafa布昆 阿卡达西ahmetile birlikte sinemaya git
  • 为什么 sql 字段名称中不应该包含逗号?

    人们一直告诉我列名中不应包含空格 我只是想知道 这是为什么 这是我为学校创建的一些数据库表遇到的问题 字段名称包括 Preble 和 Darke 相反 它们需要是 普雷布尔县 俄亥俄州 和 达克县 俄亥俄州 如果它们是行名称 我只需创建一个
  • 如何将 JSON 文本转换为 PHP 关联数组

    我将以下 JSON 对象存储在文本文件 data txt 中 player black time 0 from 2c to 3d 我使用 php 阅读 问题 有没有简单的方法可以转换 data到 PHP 关联数组 我尝试过使用json de

随机推荐