致命错误:内存不足,但我确实有足够的内存(PHP)

时间:2012-08-18 03:23:04

标签: php memory

由于我的问题越来越长,我决定重新编写整个问题,以使其更好更短。

我在具有8GB内存的专用服务器上运行我的网站。我完全清楚我需要提高php.ini设置的内存限制。我把它从128M设置为256M并设置为-1。问题仍然是持久性。

  

致命错误:内存不足(已分配786432)(尝试分配24576   在第81行的D:\ www \ football \ views \ main.php中

内存不足没有意义,因为它说只分配了786432个字节,而且需要24576个字节。

786432字节只有768千字节,而且相当小。

提示

  • 错误发生在非常随机的行上。它在第81行并不总是错误。
  • 在高峰时段,Apache只需要大约500mb的内存。我还有6GB备用。
  • 没有无限循环。
  • 该脚本占用1,042,424字节。从echo memory_get_peak_usage();
  • 获取此号码
  • MySQL的结果集很小(最多12行,纯文本,无blob数据)
  • 重要)如果我每两天重启一次Apache,则错误消失。它通常在Apache运行超过2天时发生。
  • 我已经对脚本进行了分析,你可以得到它here
  • 此专用服务器仅用于运行一个网站。该网站是一个高流量的网站,平均每分钟有1,000名访客。在高峰时段,将有1,700到2,000名访客同时访问。

服务器规范

  

操作系统:Windows 2008 R2 64位   CPU:Intel Core i5 - 4核心   RAM:8 GB
  Apache 2.2
  PHP 5.3.1
  存储:2 x 1 TB硬盘
  带宽:每月10 TB

解决方案

我终于调整并解决了问题,我想在此分享我所做的改进:

  1. favicon.ico遗失了,这与我的路线引擎相混淆。虽然我的路由引擎非常小,但是通过包含favicon.ico,它可以通过不运行我的路由引擎来减少内存使用量。我网站的大部分内容都有它,我忘了把它放在这个新的部分。
  2. 限制MaxRequestPerChild有帮助。在我的其他专用服务器中,我的MaxRequestPerChild有限制。对于这台服务器,我将其设置为0.我一直认为每个脚本都是隔离的。让我们说如果我的脚本运行800kb。完成后,Apache或PHP应该释放800kb内存。看起来它不会这样工作。限制MaxRequestPerChild确实有助于通过在限制MaxRequestPerChild之后创建新流程来防止内存泄漏,并且旧流程正在消亡。这是我的新设置。

    ThreadsPerChild      1500
    MaxRequestsPerChild  10000 
    
  3. ob_flush();确实会减少更多内存。它没有多大帮助,但每一点优化都有帮助。

  4. 我使用了xdebug,这是我以前从未使用的,正如那些试图回答这个问题的人所建议的那样。我不得不说这是一个很好的工具,我已经优化了一些东西,使它运行得更快。
  5. 我已经禁用了一些不必要的Apache模块。我试图逐个禁用它并留下几天测试,以确保它在我禁用另一个之前完美运行。我现在有所有不必要的PHP扩展禁用。
  6. 此服务器中的大多数脚本都采用传统方式(没有模板,没有数据库层,纯PHP,HTML和遗留mysql_ *函数)。说实话,它运行速度非常快,使用的内存极小。但是,随着网站越来越长,维护脚本并不容易。我试图将网站的某些部分转换为适当的框架(我自己的小框架)。之所以我使用自己的框架是因为它很小(整个框架只有3kb,只包含我需要的东西)。
  7. 切换到IIS7.5完全解决此问题

20 个答案:

答案 0 :(得分:26)

在尝试使用交换时,我遇到与服务器死亡相同的问题。这是因为 mod_php永远不会释放内存。因此,Apache进程不断增长,无论是达到apache还是PHP的内存限制,如果没有限制,都会使服务器崩溃。

重新启动apache使它产生新的细微进程但随着时间的推移运行PHP脚本,它们会一直增长直到出现问题。

解决方案是在提供一定数量的查询之后使apache杀死进程,这样它就会创建新的(some questions related to that}将MaxRequestsPerChild配置选项减少到,假设为100(默认值)到1000)。

当然,这可能会降低服务器性能,因为它需要资源来杀死和生成新进程,但至少它会保持站点正常工作。您可能想提高运行进程的数量以保持高性能,确保PHP(或apache)内存限制x max进程数不会超过服务器的物理RAM。

这是我的经历,希望有所帮助。

答案 1 :(得分:15)

首先,memory_get_peak_usage()在这里没有帮助。它只返回分配的内存量,这与导致错误的数字相同。

memory_get_usage将返回调用时分配的活动内存量。

ini_set('memory_limit', '256M');将设置PHP占用系统内存的最大容限。如果你在768K获得OOM,那么增加它将无法解决问题。

没有迹象表明您使用的是哪个版本的PHP,但我建议立即升级。有几个错误,Zend的内存管理器无法释放内存,这将导致你完全出现同样的问题。

您的本地服务器和生产服务器是否都运行相同版本的操作系统,相同的长位和相同版本的PHP?答案是否定的。

如果它与windows malloc()问题无关,因为它是一个子域,可能在VirtualHost中,并且只分配768k,这几乎听起来像操作系统问题。

访问脚本时从命令提示符运行tasklist。你看到一个额外的Apache线程,还是整个进程中的内存使用率飙升?

最后一个想法是,在表行/列的每个循环之后运行flush()和/或ob_flush();。如果出现问题,这应该清除缓冲区并为您节省一些内存。

答案 2 :(得分:8)

我首先将PHP升级到5.4+,因为某些应用程序的速度提高了50%。 他们修复了大量的内存泄漏。请参阅becnhamrks:http://news.php.net/php.internals/57760

答案 3 :(得分:6)

安装xdebug并启用探查器触发器。 生成一个探查器文件,然后发布cachegrind文件,如果你仍然无法告诉问题的根源。

编辑:当然发生内存泄漏的页面的探查器文件!

答案 4 :(得分:5)

请注意,错误为Out of memory且不是Allowed memory size [..] exhausted

因此内存泄漏在系统的其他地方。在这个繁重的查询之后,mysql服务器可能会使用大量的系统内存,而apache / php没有物理和交换。

这应该总是在同一行(和/或同一个脚本)中解释错误。

答案 5 :(得分:4)

我猜你要么没有编辑正确的php.ini,要么你还没有重新启动PHP和/或网络服务器。

在docroot中使用内容phpinfo.php创建<?php phpinfo();页面,以确保您更改了正确的php.ini。除了Web服务器正在使用的php.ini文件的位置之外,它还将声明允许的最大脚本内存。

接下来,我会向您的页面添加一些堆栈跟踪,以便您可以看到导致此问题的事件链。以下函数将捕获致命错误并提供有关所发生情况的更多信息。

register_shutdown_function(function()
{
    if($error = error_get_last())
    {
        // Should actually log this instead of printing out...
        var_dump($error);
        var_dump(debug_backtrace());
    }
});

就个人而言,Nginx + PHP-FPM是我多年来使用的,因为我离开了慢慢的'Apache。

答案 6 :(得分:3)

嘿我在我的服务器上也遇到了同样的问题。我刚刚更改了以下内容:

php.ini更改为...

memory_limit = 128M

并添加到httpd.conf

RLimitMEM 1073741824 2147483648

并重新启动apache&amp;我删除了错误:

答案 7 :(得分:3)

可能是MySQL的问题和开放连接的数量,因此当你每隔几天重新启动时它会自行排除。它们是否在脚本关闭时自动关闭?

答案 8 :(得分:2)

回顾一下(我将此答案与原始问题相距很远):

  • PHP无法分配看似少量的内存
  • 错误发生时的当前内存使用量+请求的数量小于当前有效的内存限制
  • 发生这种情况时系统可以使用6Gb
  • 因为问题是通过重新启动apache来解决的 - 它的apache阻止了内存可用于PHP

如果这些都是有效的,那么唯一可能的解释是6Gb 非常支离破碎 - 我认为这有点不太可能。您没有说过如何从Apache调用PHP - mod_php? FPM? FCGI?

我将从检查上述每个谓词开始 - 特别是免费记忆。你怎么知道发生错误时有6Gb的免费 ?更可能的原因是发生了内存泄漏,而您没有发现。

您没有提供有关如何配置apache的任何详细信息;我还要看看减少MaxRequestsPerChild和MaxMemFree。 (我对每个线程都适用的工作者apache不太熟悉 - 实际上你需要每个进程限制一次)。如果您从apache配置中提供了核心设置,那么我们可能会提出进一步的建议。

除非您广泛使用Ajax,否则请确保您的保持活动时间为2或更短。

答案 9 :(得分:1)

几天前,这件事发生在我身上。我做了一个全新的安装,它仍然发生了。每个人都看到并基于您的服务器规格。最有可能的是它是一个无限循环。它可能不在PHP代码本身上,而是在对Apa​​che的请求上。

让我们说当你访问这个网址 http:// localhost / mysite / page_with_multiple_requests

如果收到多个请求,请检查Apache的访问日志。跟踪该请求并检查可能导致系统“瓶颈”的代码(使用sendmail时我的exec())。我所谈论的瓶颈并不一定是“无限循环”。它可能是需要一些时间才能完成的功能。或者可能是某些PHP的'program execution functions'

您可能还需要检查ajax请求(页面加载时执行的请求)。如果该ajax请求重定向到相同的URL

e.g。 httpx://本地主机/ mysite的/ page_with_multiple_requests

它将重新“重做”请求

如果您发布随机行或代码本身,脚本结束可能会有帮助,也许在某处存在“循环”代码。 imho php不会只是随意调用随机行。

http://blog.piratelufi.com/2012/08/browser-sending-multiple-requests-at-once/

答案 10 :(得分:1)

以下两个事实肯定指向内存泄漏:

  1. 错误出现在代码中的不同行,
  2. 错误报告的内存分配相对较少。
  3. 我首先会选择PDO,禁用所有其他扩展,让它在一夜之间使用Siege / Apache Bench(ab)运行。您也可以尝试使用cli界面运行它(只需确保保持相同的内存限制)。

    您可以使用脚本末尾的memory_get_peak_usage()函数来查看PHP认为已使用的内存量。

    你的评论是800 kB,这没关系;绝对不是会导致内存不足的巨大内存量; - )

    最后,虽然我不建议此时升级到5.4,但升级到最新的5.3.x可能是值得的,因为自5.3.1以来已经解决了多个漏洞和泄漏

答案 11 :(得分:1)

大多数时候你会遇到这样的错误,问题在于代码。我并不是说你编写的代码很糟糕,我试图说你需要仔细观察使用这么多内存的内容。

永远记住“ PHP中的垃圾收集非常糟糕”,它不像Java,任何其他类似语言。有一种方法可以通过 gc_collect_cycle 强制执行垃圾收集,但是,在我个人看来,这不会解决您的问题。 PHP释放所有用于执行页面的内存,一旦请求 - 响应周期完成,所以你可能遇到内存问题,如果你的脚本长时间运行,就像后台脚本(Gearman等),因为,内存不会释放直到脚本正在运行。

如果你的scr,pt不是这样,并且正如你所说的那样,没有需要如此大量内存的代码,那么问题绝对是代码本身,并升级到任何版本的PHP赢了解决问题。我曾经面对过我的一个Gearman脚本,并且我的一个循环出现问题,我将一个变量附加到我的一个数组中,变量本身非常重(大约110KB的数据)。所以我建议,仔细检查你的代码。

狂喜

答案 12 :(得分:1)

我遇到了与PHP类似的问题:

1)检查错误日志。在继续之前消除每个错误。 2)考虑修改你的apache配置以消除未使用的模块 - 这将减少PHP所需的占用空间 - 这是一个很好的链接 - 它是特定于Wordpress但仍然非常有用http://thethemefoundry.com/blog/optimize-apache-wordpress/

为了让您了解我发现的错误类型,我有一些代码试图将内容发布到Facebook,Facebook然后修改了他们的API,所以这破坏了,我还使用了“内容expirator”,这基本上意味着它一直在重试将这些内容发布到Facebook,并将大量对象留在内存中。

答案 13 :(得分:1)

从探查器输出文件中我注意到了一些我不喜欢/不相信的东西,并会研究这些:

除了不知道输出数字的含义以检测异常或PHP脚本如何工作......,这不是问题吗?有一个include到相同的main.ph文件,看起来像一个递归的东西?

2121 fl=D:\www\football\views\main.php
2122 fn=include::D:\www\football\views\main.php

注意文件D:\www\football\views\main.php多次使用一些字符串函数,我猜它是在查询返回的数据上调用这些函数:

strlen
substr
strtotime

如果像在C语言中一样,这些函数需要字符串null终止或字符串终结符的另一端以避免内存问题,我会查看查询返回的字符串。

您可以发布您网站的网址吗?

答案 14 :(得分:1)

这是PHP v 5.2 for Windows中的已知错误,它至少存在于5.2.3版本中:https://bugs.php.net/bug.php?id=41615

没有任何建议的修复程序对我们有帮助,我们将不得不更新PHP。

答案 15 :(得分:1)

尝试在fcgid上运行php,这可能会有所帮助:

  

这些是您在运行PHP时会看到的经典错误   Apache模块。几个月来我们一直在努力解决这些错误。切换到   通过mod_fcgid使用PHP(正如James推荐的那样)将解决所有这些问题   问题。确保您拥有最新的Visual C ++ Redistributable   包安装:

     

http://support.microsoft.com/kb/2019667

     

另外,我建议切换到64位版本的MySQL。不真实   之所以再次运行32位版本。

来源:Apache 2.4.6.0 crash due to a problem in php5ts.dll 5.5.1.0

答案 16 :(得分:1)

致命错误:内存不足(分配已解决
我有类似的问题,几个月没有解决方案。最后我检查了一个apache文件夹,即(\ apache \ conf \ extra)我遇到了这个控制apache内存分配的文件。文件名是 httpd-mpm 在那个文件中你要将MaxMemFree设置为2048更高的东西,我把我的第一个MaxMemFree(IfModule!mpm_netware_module)拿到10000然后做第二个MaxMemFree为5000 IfModule mpm_netware_module。

这些解决了我的问题。希望它有所帮助

答案 17 :(得分:0)

我会说服务器的物理/交换内存不足,所以PHP无法分配足够的内存。

您可以在此处粘贴free的输出吗?

答案 18 :(得分:0)

对于我的情况,由于巨大的选择查询(数十万返回的结果)而触发了此错误。

在我的数据库中添加数百万条记录后立即出现,以测试WordPress的可扩展性,所以这是我唯一可能的原因。

答案 19 :(得分:0)

我知道这是一个旧线程,但是这是我解决它的经验。

我的服务器是运行Apache的托管服务。

当我的限制为256Mb时,我的脚本崩溃了,内存不足6Mb,是吗?

它正在通过HTTP回调从我的客户端上运行的javascript同步调用,并在大约550次调用后崩溃。 与无能的“升级支持”人员浪费了很多时间之后,我的脚本现在可以神奇地运行了。

他们说,他们所做的只是重置php.ini,但我检查了差异: enter image description here

我看不到任何与内存不足错误有关的更改。

我怀疑Web服务器内存泄漏,而我的“升级支持”人员则以重置php.ini为幌子。而且,实际上,我不是阴谋理论家。