【问题标题】:PHP Allowed memory size Memory size exhaustedPHP 允许的内存大小 内存大小已用完
【发布时间】:2015-11-30 15:20:50
【问题描述】:

我正在尝试使用 google API 在地图上显示用户。现在,当用户数增加到 12000 时,我得到了一个内存异常错误。目前我将内存从 128 增加到 256。但我确信当它的 25000 用户再次出现同样的错误时。

错误是, Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 30720 bytes) in /var/www/html/digitalebox_v2_20150904_100/protected/extensions/bootstrap/widgets/TbBaseMenu.phponline 193 致命错误:类声明不能嵌套in/var/www/html /yii-1.1.14.f0fee9/framework/collections/CListIterator.phponline 20`

我的代码,

$criteria = 新 CDbCriteria(); $criteria->condition = 't.date BETWEEN :from_date AND :to_date';
$modelUsers = User::model()->findAll($criteria); foreach ($modelUsers 作为 $modelUser) { $fullAddress = $modelUser->address1 。 ',' 。 $modelUser->zip 。 ' ' 。 $modelUser->城市。 ',' 。 Country::model()->findByPk($modelUser->countryCode)->countryName; }

当这个 $modelUsers 有 12000 条记录时,这个内存问题来自它的 12000 个用户对象。

我应该怎么做以防止将来出现此类问题?运行 php 应用程序所需的最小内存大小是多少?

【问题讨论】:

  • 为什么要选择所有用户,而不仅仅是您需要的数据?解决此问题的方法是向数据库询问相关数据。您不必使用模型解决所有问题。查询地址然后在地图上显示 25000 个地址并没有错,尽管这也是相当多的数据(人类可以在一张地图上区分所有 25000 人?)。
  • 这是一个公平的观点
  • 我仍然需要过滤器的数据来自大约 12000 条记录。
  • 你会处理所有的 12000 吗?您要求所有列吗?或者只是您将使用的列?
  • 假设你需要处理12K,分块读取和处理。请记住,每行中的每个字段在 PHP 中占用 40 个字节或更多。

标签: php mysql performance memory yii


【解决方案1】:

php.ini 中增加memory_limit 的值。然后重新启动 Apache 或任何正在运行的 PHP。请记住,您在此处添加的内容需要从同一台机器上运行的其他程序(例如 MySQL 及其innodb_buffer_pool_size)中删除。

【讨论】:

    【解决方案2】:

    我会以与建议的完全不同的方式解决这个问题。我会放弃整个模型概念,我会向 MySQL 查询地址。您可以查询 MySQL,使其返回已经连接的地址,这意味着您可以避免在 PHP 中连接它 - 避免浪费内存。

    下一步将使用PDO 并发出无缓冲查询。这意味着 PHP 进程不会在其内存中存储全部 12 000 条记录 - 这样可以避免耗尽内存。

    最后一步是输出结果 - 当您遍历无缓冲查询时,您可以一次使用输出单行(或 10 行)。

    这样发生的事情是您用 CPU 换取 RAM。由于您不知道需要多少 RAM,因此最好的方法是尽可能少地使用。

    使用无缓冲查询和刷新 PHP 的输出缓冲区似乎是适用于您的用例的唯一可行方法,因为您无法避免输出大量数据。

    【讨论】:

    • 第 3 方软件阻碍的另一个例子。谢谢你的轶事。
    【解决方案3】:

    当您调用 findAll 时,它会及时加载所有记录,因此您会收到 end memory 错误。对于这种情况,Yii 有 CDataProviderIterator。它允许对大型数据集进行迭代,而无需将整个数据集保存在内存中。

    $dataProvider = new CActiveDataProvider("User");
    $iterator = new CDataProviderIterator($dataProvider);
    foreach($iterator as $user) {
       $fullAddress = $modelUser->address1 . ', ' . $modelUser->zip . ' ' . $modelUser->city . ', ' . Country::model()->findByPk($modelUser->countryCode)->countryName;
    }
    

    【讨论】:

    • 我可以将 CDbCriteria 对象传递给 CActiveDataProvider 吗?就像我们可以通过 findAll(CDbCriteria) 一样?如果是这样,这将有助于解决我的问题。
    • 是的,你可以。看文档yiiframework.com/doc/api/1.1/CActiveDataProvider或者使用gii生成CRUD,在模型的search()方法中找到例子。
    【解决方案4】:

    也许再增加一点内存,看看是否能解决问题。尝试将其设置为 512M 或 1024M。我会根据我自己的经验告诉你,如果你试图加载谷歌地图标记,那么标记的数量可能会使地图崩溃。

    【讨论】:

    • 那么当谷歌地图标记崩溃时你做了什么来修复它?
    • 我最终使用了他们的融合表解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-05-09
    • 2011-05-05
    • 1970-01-01
    • 2013-02-08
    • 2020-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多