70

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

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

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

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

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

提示

  • 错误发生在非常随机的行上。它并不总是在第 81 行出错。
  • 在高峰期,Apache 只占用大约 500mb 的内存。我还有 6GB 可用空间。
  • 没有无限循环。
  • 该脚本占用 1,042,424 个字节。从中获取此号码echo memory_get_peak_usage();
  • MySQL 的结果集很小(最多 12 行,纯文本,没有 blob 数据)
  • 重要)如果我每两天重新启动一次 Apache,错误就消失了。它通常发生在 Apache 运行超过 2 天时。
  • 我已经包含了分析脚本,你可以在这里得到它。
  • 这个专用服务器纯粹是用来运行一个网站的。该网站是一个高流量网站,平均每分钟有 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 内存。似乎它不以这种方式工作。LimitedMaxRequestPerChild确实有助于通过在受限之后创建新进程来防止内存泄漏,MaxRequestPerChild并且旧进程正在死亡。这是我的新设置。

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

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

20 回答 20

31

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

重新启动 apache 会生成新的苗条进程,但随着时间的推移它们会运行 PHP 脚本,它们会不断增长,直到出现问题。

解决方案是让 apache 在提供一定数量的查询后终止进程,以便创建新的(有一些与此相关的问题)将MaxRequestsPerChild配置选项减少到,比如说 100(默认为 1000)。

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

以上是我的经验,希望对你有帮助。

于 2012-08-29T12:42:31.577 回答
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();如果出现问题,这应该会清除缓冲区并为您节省一些内存。

于 2012-08-28T16:17:29.483 回答
8

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

于 2012-08-27T08:55:59.530 回答
7

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

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

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

于 2012-08-29T09:34:38.793 回答
6

安装 xdebug 并启用分析器触发器。生成一个分析器文件,然后如果您仍然无法确定问题的根源,请发布 cachegrind 文件。

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

于 2012-08-27T09:10:35.697 回答
4

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

phpinfo.php在您的 docroot 中创建一个包含内容的页面,<?php phpinfo();以确保您更改的是正确的php.ini. 除了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 以来多年来一直使用的。

于 2012-08-29T19:32:01.283 回答
4

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

这些解决了我的问题。希望能帮助到你

于 2017-10-24T10:33:33.773 回答
3

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

更改php.ini为...

memory_limit = 128M

并添加到httpd.conf

RLimitMEM 1073741824 2147483648

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

于 2012-09-01T06:07:40.257 回答
3

可能是 MySQL 和打开连接数的问题,因此为什么每隔几天重新启动时它会自行解决。他们是否在脚本关闭时自动关闭?

于 2012-08-29T14:07:14.517 回答
2

回顾一下(我添加的这个答案与原始问题相距甚远):

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

如果这些都是有效的,那么唯一可能的解释是 6Gb非常分散——我认为这不太可能。您没有说如何从 Apache 调用 PHP - mod_php?每分钟?Fcgi?

我将从检查上述每个谓词开始——尤其是空闲内存谓词。你怎么知道发生错误时有 6Gb 可用?更可能的原因是发生了您没有发现的内存泄漏。

您没有提供有关如何配置 apache 的任何详细信息;我还想看看减少 MaxRequestsPerChild 和 MaxMemFree。(我对每个线程都适用的 worker apache 不是很熟悉——实际上你需要对每个进程进行限制)。如果您从 apache 配置中提供了核心设置,那么也许我们可以提出进一步的建议。

除非您广泛使用 Ajax,否则请确保您的 keepalive 时间为 2 或更少。

于 2012-08-31T12:57:31.923 回答
1

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

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

如果您的 scr,pt 不是上述情况,并且正如您所说,没有需要如此大量内存的代码,那么问题肯定出在代码本身,升级到任何版本的 PHP 都无法解决问题。我曾经遇到过我的一个 Gearman 脚本,我的一个循环出现了问题,我将一个变量附加到我的数组之一,变量本身非常重(大约 110KB 的数据)。所以我建议,仔细检查你的代码。

狂欢

于 2012-09-01T11:02:54.827 回答
1

我对 PHP 有类似的问题:

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

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

于 2012-09-01T13:56:28.820 回答
1

几天前发生在我身上。我做了一个全新的安装,它仍然发生。据每个人都看到并基于您的服务器规格。很可能它是一个无限循环。它可能不在 PHP 代码本身上,而是在向 Apache 发出的请求上。

假设您访问此网址http://localhost/mysite/page_with_multiple_requests

如果收到多个请求,请检查 Apache 的访问日志。跟踪该请求并检查可能导致系统“瓶颈”的代码(使用 sendmail 时我的 exec())。我所说的瓶颈不需要是“无限循环”。它可能是一个需要一些时间才能完成的功能。或者也许是一些 php 的“程序执行功能

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

例如 httpx://localhost/mysite/page_with_multiple_requests

它会重新“重做”请求

如果您在脚本结束的地方发布随机行或代码本身,可能会有所帮助,那里可能有一个“循环”代码。恕我直言 php 不会只调用随机行。

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

于 2012-08-30T07:34:46.153 回答
1

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

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

于 2013-09-26T08:51:41.760 回答
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 由于 php5ts.dll 5.5.1.0 中的问题而崩溃

于 2015-03-19T10:23:12.253 回答
1

从探查器输出文件中,我注意到一些我不太喜欢/不太信任的事情,并会研究这些:

除了不知道检测异常的输出数字的含义或 PHP 脚本如何工作之外......,这不是问题吗?对同一个 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终止字符串或字符串终止符的其他结尾以避免内存问题,我会查看您的查询返回的字符串。

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

于 2012-09-01T14:09:28.313 回答
1

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

  1. 错误出现在代码的不同行,
  2. 该错误报告相对较小的内存分配。

我会首先选择 PDO,禁用所有其他扩展,然后使用 Siege / Apache Bench (ab) 之类的东西让它在一夜之间运行。您也可以尝试使用cli界面运行它(只需确保保持相同的内存限制)。

您可以memory_get_peak_usage()在脚本末尾使用该函数来查看 PHP 认为它已经使用了多少内存。

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

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

于 2012-08-27T09:17:37.287 回答
0

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

你能粘贴这里的输出free吗?

于 2012-08-27T21:54:25.143 回答
0

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

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

我的脚本在 6Mb 内存不足时崩溃了,而我的限制是 256Mb - 疯了,是吗?

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

他们说他们所做的只是重置 php.ini,但我检查了差异: 在此处输入图像描述

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

我怀疑我的“升级支持”人员以重置 php.ini 为幌子隐藏了 Web 服务器中的内存泄漏。而且,真的,我不是阴谋论者。

于 2020-09-23T00:45:58.477 回答
0

就我而言,这个错误是由于一个巨大的选择查询(数十万个返回结果)而触发的。

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

于 2017-10-24T10:15:27.487 回答