在两个 foreach 循环中使用“继续 2”时 php 5.5 内存泄漏?

Posted

技术标签:

【中文标题】在两个 foreach 循环中使用“继续 2”时 php 5.5 内存泄漏?【英文标题】:php 5.5 memory leak when using "continue 2" inside two foreach loops? 【发布时间】:2014-04-22 22:47:24 【问题描述】:

我刚刚遇到了一个奇怪的内存泄漏问题。我设法将问题追溯到以下代码:

<?php
$data=array();
for($c=0; $c<32768; $c++)
    $data[$c]=array(1, 2, 3);
$filter=array(1, 2, 3);

for($kc=0; $kc<25600; $kc++)

    $cm=memory_get_usage(true);
    $pm=memory_get_peak_usage(true);
    echo "<b>loop $kc: current_memory: $cm, peak_memory: $pm...</b><br>";
    flush();

    foreach($data as $entry)
        foreach($filter as $pattern)
            continue 2;

?>

输出:

loop 0: current_memory: 12582912, peak_memory: 12582912...
loop 1: current_memory: 20709376, peak_memory: 20709376...
loop 2: current_memory: 28835840, peak_memory: 28835840...
loop 3: current_memory: 36962304, peak_memory: 36962304...
loop 4: current_memory: 45088768, peak_memory: 45088768...
loop 5: current_memory: 53215232, peak_memory: 53215232...
loop 6: current_memory: 61341696, peak_memory: 61341696...
loop 7: current_memory: 69468160, peak_memory: 69468160...
loop 8: current_memory: 77594624, peak_memory: 77594624...
loop 9: current_memory: 85721088, peak_memory: 85721088...
loop 10: current_memory: 93847552, peak_memory: 93847552...
loop 11: current_memory: 101974016, peak_memory: 101974016...
loop 12: current_memory: 110100480, peak_memory: 110100480...
loop 13: current_memory: 118226944, peak_memory: 118226944...
loop 14: current_memory: 126353408, peak_memory: 126353408...
loop 15: current_memory: 134479872, peak_memory: 134479872...
loop 16: current_memory: 142606336, peak_memory: 142606336...
loop 17: current_memory: 151257088, peak_memory: 151257088...
loop 18: current_memory: 159383552, peak_memory: 159383552...
loop 19: current_memory: 167510016, peak_memory: 167510016...
loop 20: current_memory: 175636480, peak_memory: 175636480...
loop 21: current_memory: 183762944, peak_memory: 183762944...
loop 22: current_memory: 191889408, peak_memory: 191889408...
loop 23: current_memory: 200015872, peak_memory: 200015872...
loop 24: current_memory: 208142336, peak_memory: 208142336...
loop 25: current_memory: 216268800, peak_memory: 216268800...
loop 26: current_memory: 224395264, peak_memory: 224395264...
loop 27: current_memory: 232521728, peak_memory: 232521728...
loop 28: current_memory: 240648192, peak_memory: 240648192...
loop 29: current_memory: 248774656, peak_memory: 248774656...
loop 30: current_memory: 256901120, peak_memory: 256901120...
loop 31: current_memory: 265027584, peak_memory: 265027584...
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 40 bytes) in xxx

当我删除“continue 2”语句并使用简单的“break”或“continue”时,内存使用量保持不变。 谁能确认这种奇怪的行为? 我是否在 php 5.5 中发现了内存泄漏错误? 使用 php-cli 不会显示这种奇怪的行为。只有在 apache 中使用 php 作为 mod_php 才会显示这种行为。

我的系统:

$ php --version
PHP 5.5.11-2 (cli) (built: Apr  8 2014 11:42:22) 
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies

$ apache2ctl status
Apache Server Status for localhost (via ::1)

   Server Version: Apache/2.4.9 (Debian)
          mod_fastcgi/mod_fastcgi-SNAP-0910052141 PHP/5.5.11-2
          mod_perl/2.0.8 Perl/v5.18.2

   Server MPM: prefork
   Server Built: Mar 29 2014 21:52:01

我正在进行当前的 Debian 测试 (Jessie)。

感谢您的帮助!

【问题讨论】:

在本地和viper7 上测试了您的代码,并且没有泄漏。 在3v4l.org 上没有看到任何版本的任何证据,尽管他们认为它滥用了他们的资源......抱歉 3v4l 伙计们 嗯,这很奇怪。我不知道我的 php 版本有什么特别之处。好的,我刚刚在 php-cli 中测试了我的代码 --> 没有内存泄漏。我正在使用 apache 2.4.9。 (更新了我的问题并包含了我的 apache 版本信息)。 你能禁用 Zend OPcache 吗?我之前遇到过问题(没有注意到一些使用过的文件的变化)。 @LeventePánczél 是的!就是这样!我禁用了 opcache,一切都按预期运行。从 PHP 5.4 到 5.5 的更新覆盖了我的 php.ini,这似乎启用了 opcache。感谢您的提示!你想写一个答案,以便我接受吗? :) 【参考方案1】:

等一下!!

你不应该禁用 opcache:和缓存一样,opcache 执行优化。

优化意味着 opcache改变编译后的操作码

我确信调优优化会告诉你错误是在哪里引入的,这意味着你可以在 bugs.php.net 上创建一个错误报告,我们有机会为每个人修复问题。

请花点时间来做这件事,拜托。

调优优化

Opcache 有几个优化通道,https://gist.github.com/krakjoe/962e54c38b155f896b00

配置哪些通过运行是在您的配置中更改opcache.optimization_level 的问题,这是一个位掩码,默认为0xffffffff

如果您需要调试帮助,请访问 EFnet 上的#php.pecl。

注意:要在 php-cli 中启用 opcache,请将 opcache.enable_cli 更改为 1,这将允许您在控制台中进行测试,应该会显示相同的行为

【讨论】:

好的...我会试试的。位掩码中的哪个条目对应于哪个优化通道?传1有0x00000001,传2有0x00000002等等?【参考方案2】:

仅在 5.5 和 5.6.3 (https://bugs.php.net/bug.php?id=65743) 下验证“继续 2”错误。一种解决方法是利用“goto-hack”而不是继续,而是“返回”到第一个 foreach 中定义的标签...我知道,f*gly 但有效(with opcache)

【讨论】:

现在该错误已修复,请参阅此提交:git.php.net/… 这有望包含在即将发布的 5.5.21 和 5.6.5 版本中 是的,在这些版本中已修复,如更改日志中所示:php.net/ChangeLog-5.php#5.5.21

以上是关于在两个 foreach 循环中使用“继续 2”时 php 5.5 内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用foreach循环进入另一个foreach循环来遍历c​​odeigniter中的两个不同的数据表?

foreach跳出循环不往下走

绑定两个 ForEach 循环以更新每个项目单元格

foreach 循环中的两个数组

PDO - 对多个 foreach 循环使用相同的查询

在Foreach循环中使用时不会加载UI