首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >php脚本中的内存泄漏

问php脚本中的内存泄漏
EN

Stack Overflow用户
提问于 2010-04-08 22:29:52
回答 5查看 2.2K关注 0票数 4

我有一个php脚本,它运行mysql查询,然后循环结果,在该循环中还运行几个查询:

代码语言:javascript
复制
    $sqlstr = "SELECT * FROM user_pred WHERE uprType != 2 AND uprTurn=$turn ORDER BY uprUserTeamIdFK";
    $utmres = mysql_query($sqlstr) or trigger_error($termerror = __FILE__." - ".__LINE__.": ".mysql_error());
    while($utmrow = mysql_fetch_array($utmres, MYSQL_ASSOC)) {
// some stuff happens here    
//  echo memory_get_usage() . " - 1241<br/>\n";
        $sqlstr = "UPDATE user_roundscores SET ursUpdDate=NOW(),ursScore=$score WHERE ursUserTeamIdFK=$userteamid";
        if(!mysql_query($sqlstr)) {
            $err_crit++;
            $cLog->WriteLogFile("Failed to UPDATE user_roundscores record for user $userid - teamuserid: $userteamid\n");
            echo "Failed to UPDATE user_roundscores record for user $userid - teamuserid: $userteamid<br>\n";
            break;
        }
    unset($sqlstr);
    //  echo memory_get_usage() . " - 1253<br/>\n";
// some stuff happens here too
}

更新查询永远不会失败。

由于某种原因,在memory_get_usage的两次调用之间,增加了一些内存。由于大循环运行了大约500.000次或更多次,最终它实际上增加了大量的内存。我是不是漏掉了什么?

有没有可能内存实际上并没有添加到两个调用之间,而是在脚本的另一个地方?

编辑:一些额外的信息:在循环之前大约是5mb,在循环之后大约是440mb,并且每个更新查询增加大约250字节。(其余的内存被添加到循环中的其他位置)。我没有发布更多“其他东西”的原因是因为它大约有300行代码。我张贴了这个部分,因为它看起来是添加了最多内存的地方。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-04-16 16:30:10

从php.net memory_get_usage manual

参数

real_usage将其设置为TRUE,以获取从系统分配的实际内存大小。如果未设置或设置为FALSE,则只报告emalloc()使用的内存。

当这个参数设置为true时,脚本并没有像我预期的那样增加内存。

票数 1
EN

Stack Overflow用户

发布于 2010-04-09 10:53:07

只有在“内存耗尽”错误杀死脚本的情况下,内存泄漏才会成为问题。PHP会很高兴地自己对任何不常用的对象/变量进行垃圾回收,但收集器不会踢它,直到它不得不这样做-垃圾收集可能是一个非常昂贵的操作。

即使你经常重用相同的对象/变量,也会看到内存使用量攀升,这是很正常的-直到内存使用量超过一定的水平,收集器才会启动并清理房间。

我怀疑,如果您将userID批处理到组中,并发出更少的更新,每次更改更多的记录,那么您可以让事情运行得更快。例如,执行以下操作:

代码语言:javascript
复制
UPDATE user_roundscores SET ursUpdDate=NOW() WHERE ursUserTeamIdFK IN (id1, id2, id3, id4, id5, etc...)

而不是为每个用户更新一次。通过DB接口层的往返次数更少,在服务器上的时间更长=运行速度更快。

同样,考虑一下现在将其扩展到数百万用户的影响,正如您在评论中所说的那样。一百万个单独的更新将花费大量的时间来运行,因此NOW()不会是一个“常量”。如果跑完全程需要5分钟,那么你会得到各种各样的ursUpdDate时间戳。您可能需要考虑在服务器端变量中缓存单个NOW()调用,并针对该变量发出更新:

代码语言:javascript
复制
 SELECT @cachednow :p NOW();
 UPDATE .... SET ursUpDate = @cachednow WHERE ....;
票数 4
EN

Stack Overflow用户

发布于 2010-04-08 23:23:14

最好的方法可能是获取所有userIds并将它们刷新到一个文件中。然后运行一个新的脚本,该脚本将管道派生到x数量的工人无人机。然后,在他们完成每个列表时,只需给他们一个小的userIds列表进行处理。使用多个cpus/核心/服务器,您可以更快地完成任务。如果一个工人失败了,只需启动一个新的。要使用其他服务器作为工作线程,可以从工作线程使用curl/fopen/soap/etc调用它们。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2600724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档