gpt4 book ai didi

php - 对PHP脚本的多个jQuery.load()调用导致“无法分配内存:无法创建子进程”错误

转载 作者:行者123 更新时间:2023-12-01 05:50:36 25 4
gpt4 key购买 nike

我有一个HTML页面,该页面多次调用jQuery.load('test.php')。 test.php的输出为“ 256kB”,如下所示,64个请求x 256kb应该花费16MB。但是,cPanel的资源使用情况表明,一次运行64个请求实际上需要154 MB(或每个请求2.4 MB)的开销。多个周期违反了我的共享主机1GB虚拟内存限制,并导致错误:


(12)无法分配内存:无法创建子进程:/ opt / suphp / sbin / suphp


由于静态文件不会发生这种情况,因此我怀疑PHP有一些开销,但是多少呢?为何脚本完成后没有立即收回虚拟内存?我试过'die'和'exit()'无效。有没有一种方法可以强制PHP(v5.2.17)进行垃圾回收?

test.html:

<table>
<tr>
<td id="column_1"></td>
<td id="column_2"></td>
<td id="column_3"></td>
<td id="column_4"></td>
</tr>
</table>

<script>
function loadPage() {
$('<div>').load('/test.php', function (response) {
$('#column_1').append(response);
});
$('<div>').load('/test.php', function (response) {
$('#column_2').append(response);
});
$('<div>').load('/test.php', function (response) {
$('#column_3').append(response);
});
$('<div>').load('/test.php', function (response) {
$('#column_4').append(response);
});
}
$(document).ready(function () {
for ( var j = 0; j < 16; j++ ) {
loadPage();
}
});
</script>


test.php:

echo memory_get_peak_usage(true) / 1024 . 'kB';


(注意:我实际上没有运行jQuery.load()64次,但是导致此问题的原始错误是大约12个请求,每个请求占用5MB的内存。此后,我想到了一种更好的方法,它需要较少的请求,但需要以确保当应用程序期望同时接收多个同时请求时,不会在生产中再次出现此错误)

最佳答案

PHP脚本的输出与PHP(加上Web服务器)进程实际使用的内存无关。开销取决于加载的模块和服务器配置;基本上在您的设置中,每个请求都产生一个suphp实例,即使它是动态链接的(不是吗?),也会重复很多内部结构。我发现Apache PHP模块在内存使用方面节俭(但它也取决于加载的模块,通常甚至不取决于PHP模块;因此,如果要跳转,请检查您的配置)。

您可以使用PHP memory reporting functions更好地评估请求在其生命周期内的内存占用,不仅是在结束时,还可以查看哪些操作消耗了最多的内存。使用unset()释放不需要的对象通常是有益的。

您可以一个接一个地运行请求,并将中间结果保存到磁盘文件中,以减少总体内存占用。然后,最后一个调用可以收集结果并将其与passthru函数之一一起发送。

ob_end_clean()禁用缓冲可能有助于减少服务器进程的内存使用(即使它对PHP部分无效)。在您的情况下,我不确定该进程是否有效,因为该进程实际上是一个独立的suphp二进制文件,但是您始终可以尝试看看会发生什么。

在大型JSON对象中合并请求

如果多个调用使用相同的输入参数或“可合并”参数,则可以尝试将这些调用合并到一个调用中,因此也可能使所有操作变得更快:您无需返回一个对象,而是将多个对象合并为一个对象

Header('Content-Type: application/json');
die(json_encode(array(
'column1' => 'Output for the call to column1',
'column2' => ...
));


在jQuery中,您将得到所有这些对象,并将它们分派到需要去的地方

function loadPage() {
$.get('/test-big.php', {
parcol1: 'parameter the code generating column 1'
}, function(data, textStatus, jqXHR) {
$('#column_1').append('<div>').html(data.column1);
$('#column_2').append('<div>').html(data.column2);
...
});
}


即使满足所有请求的总时间更长,然后在“页面上发生了某些事情”之前会有更长的延迟,但我还是觉得这种方法几乎总是可取的,原因有以下几个:


它是一个HTTP连接,节省了连接开销。使用流水线HTTP不再是很大的优势,但仍然是优势。
HTTP服务器通常使用的压缩功能具有“性能曲线”,并且不会压缩,例如第一个kB以及第二个及其后的kB,尤其是在重复次数很多的情况下。因此,发送五个2 Kb数据包会将它们转换为五个0.5 Kb数据包,总计2.5 Kb。但实际上第一个Kb变为0.3,第二个Kb变为0.2;因此,发送一个10-Kb数据包会将其转换为0.3 + 0.2 + 0.18 + 0.18 + ... = 2 Kb,这可以节省20%的成本。
除非请求是完全不相关的,并且完全击中应用程序的不同区域(这是极不可能的),否则它们都会产生相同的设置成本(数据库连接,过滤器,缓冲区,加载类,缓存...)。只承担一次而不是几次的费用是一笔不小的交易。
您使用的资源要少得多:不仅有RAM(一个开销与许多开销),还有一个数据库连接,一个缓存连接,依此类推。的确,总资源使用量与请求数不成比例,因为其中一些请求甚至在其他一些请求甚至尚未启动之前就已终止,但是通过这种方式,您可以确保比例是恒定的。
如果这些请求之间具有很高的相关性(例如,您要求一个库存列的总和显示一个信号量图形,而另一个库存量的总和显示另一个信号量...),则可以重新设计SQL查询或其他任何内容。以便一次返回所有信息。可以用 SELECT opening, closing FROM nyse WHERE st='XXXX';代替二十个XXXX的 SELECT st, opening, closing FROM nyse WHERE st IN ('XXXX1','XXXX2',...);值,并用一个仅比第一个慢一点的单个查询替换二十个查询。这并非总是可以做到的,但是它经常发生,因此值得牢记。通过适当地设计jQuery代码,您甚至可以通过单个 .each循环调度所有答案(例如,如果每个目标DIV的ID与该代码相同,则您可以发送包含例如< cc>)。

关于php - 对PHP脚本的多个jQuery.load()调用导致“无法分配内存:无法创建子进程”错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22724525/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com