在composer个别库中,会include配置文件,在调用时会重复include,并且不会释放内存,导致实际业务不复杂,但是循环之后内存占满进程被kill掉。分享一下这个过程,开发时要留意。
pinyin.php:
<?php
return [
'key1' => 'value1',
];
demo.php:
<?php
$list = []; // 假设这里有10万条数据库记录要处理
foreach ($list as $item) {
$pinyin = include('pinyin.php');
unset($pinyin); // 变量内存释放了,但是include的那部分内存无法释放
}
这里就没办法主动释放内存,这种情况我在composer的拼音库(overtrue/pinyin)遇到过一次。
<?php
use Overtrue\Pinyin\Pinyin;
foreach ($db_list as $item) {
$pinyin = Pinyin::sentence('你好,世界');
}
因为这里作者为了开发方便封装了过程,但是在循环引用时候其内部逻辑重复include,最终导致进程内存占满被kill掉
还有一种情况是:
PHPQuery库,不停的向一个变量追加string,但是并未释放,因为他使用的是静态类,所以在用完之后要调用phpquery的释放方法来释放内存。
jaeger/querylist 库因为引用的是PHPQuery,所以也存在这个问题。
php为了高性能并不会每次释放变量都会将内存交还给操作系统,而是留着下次复用。业务不用调用unset去主动释放变量,因为临时变量函数或方法运行完毕会自动释放。
不断include并不会导致内存泄露问题。
Pinyin::sentence('你好,世界');本地经过10次-1000次测试也没出现内存泄露问题。
PHPQuery库因为没有测试代码并未测试。
另外webman有内存检测机制,如果某个进程内存增长到一定程度会自动reload对应进程释放内存,所以即使有内存泄露也不用担心。
感谢作者大大认真的验证,希望大家都可以借鉴。