php - 为什么在匿名函数上使用 `unset` 时使用 `eval` 以后不会释放内存?
问题描述
下面非常简单的 PHP 代码可以完美运行,我的意思是,它什么也不做,同时它几乎不使用任何系统内存。
<?php
set_time_limit(0);
ini_set('memory_limit','-1');
for ($i=0;$i<100000000;$i++) {
$bbb = function() {
return true;
};
unset($bbb);
}
?>
虽然下面的代码非常相似,但是如果你运行它,几分钟后你会崩溃你的系统,因为它会消耗你所有的系统 RAM。
<?php
set_time_limit(0);
ini_set('memory_limit','-1');
for ($i=0;$i<100000000;$i++) {
eval('
$bbb = function() {
return true;
};
');
unset($bbb);
}
?>
我的实际$bbb
功能要复杂得多,这是我的 AI 输出的结果,所以我真的需要eval
在这种情况下使用。我完全了解安全隐患。
我只是想知道如何解决这个问题。在第二种情况下,如何让 PHP/APACHE 释放内存(GC 可能是 curlprit)?
注意:我正在使用带有 PHP 7.4 的 Windows 10
编辑
根据@Nigel Ren 的建议(看起来非常好),我尝试了这个:
<?php
set_time_limit(0);
ini_set('memory_limit','-1');
for ($i=0;$i<100000000;$i++) {
require("test.php");
unset($bbb);
}
?>
“test.php”文件有这个:
<?php
$bbb = function() {
return true;
};
?>
但是这个建议仍然消耗大量内存,它没有被清除!即使我使用gc_mem_caches();
GC 仍然没有清除内存。也许我从你的建议@@Nigel Ren 中理解了一些错误?
解决方案
请参阅 Chris对此错误报告的最后评论。
为了后代的缘故,我会在这里复制它:
我最近对 eval() 行为感兴趣,我可以确认到执行时内存使用率会更高。然而,这并不是一个真正的错误,而是 eval() 的基本编写方式:
- 它创建一个包含代码的临时文件(有时它存储在内存中)
- 然后它使用普通的 include() 函数包含该临时文件
如您所见,您执行的 eval() 越多,它将触发的 include() 越多,从而导致无法释放的内存使用...
因此,使用时内存使用量增加的原因eval
是它包含临时文件。有多种方法可以取消包含文件,因此您使用eval
的越多,您最终将使用的内存就越多。
免责声明:以下纯属猜测,我尚未验证这是否有效
至于解决此问题的潜在解决方法,既然您说您需要使用eval
,您可以考虑使用扩展pcntl
来分叉一个进程。
它可能会更慢,但是如果您可以eval
将代码的 -ing 部分分叉到一个单独的进程,该进程可以在完成后优雅地终止,那么应该清除在该子进程中执行的“包含”。这可能是限制应用程序中内存使用的一种方法。
推荐阅读
- java - Spring boot jpa查询无法更新字段
- crystal-lang - Crystal 构建失败并出现错误 - 找不到 -levent
- html - 带有绝对定位的图像上的文本
- spring - Swagger - 定义多部分文件请求的最大大小限制
- node.js - Reactjs 没有建立到 Peerjs 服务器的连接
- python - 获取满足条件的列名
- java - 后退按钮工具栏中的触摸区工作不正常
- security - Apps 脚本库安全性
- python - 如何连接列表和数据框以在 Python 中创建字典
- node.js - NodeJS 数组和 firebase 引用获取垃圾收集