为什么 PHP unserialize 会有内存泄露
最近写一个 PHP 服务,PHP 版本为 swoole PHP 环境二进制版 7.x,其中部分逻辑涉及到把 PHP 变量写入到文件中,后续处理的时候读出来,一开始使用 serialize
和 unserialize
实现,但是运行不久就直接超内存了,最后发现是 unserialize
造成的内存泄露
例子:
测试数据: serialize
序列化字符串
[www@chengqm test]$ cat serialize_str
a:1:{s:4:"test";s:1024:"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";}
测试数据: json
序列化字符串
[www@chengqm test]$ cat json_str
{"test":"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"}
然后是 PHP 代码,分别反序列化这两个文件的内容,前后输出内存使用情况
<?php
echo PHP_EOL;
echo 'before unserialize: ' . memory_get_usage() . PHP_EOL;
$serialize_str = file_get_contents('./serialize_str');
$array = unserialize($serialize_str);
unset($serialize_str);
unset($array);
echo 'after unset args: ' . memory_get_usage() . PHP_EOL;
echo PHP_EOL;
echo 'before decode_json: ' . memory_get_usage() . PHP_EOL;
$json_str = file_get_contents('./json_str');
$array = json_decode($serialize_str, True);
unset($json_str);
unset($array);
echo 'after unset args: ' . memory_get_usage() . PHP_EOL;
结果
[www@chengqm test]$ php-swoole test.php
before unserialize: 625048
after unset args: 625192
before decode_json: 625192
after unset args: 625192
unserialize
的某部分内存没有释放,json_decode
的已经释放了
问题: 为什么会有部分内存没有释放,是 BUG 还是 PHP 的某项特性
------------------- 问题更新 ---------------------
上面代码写错变量,重新测一下,这次没有读取文件,json_decode 放在前面
<?php
echo PHP_EOL;
echo 'before decode_json: ' . memory_get_usage() . PHP_EOL;
$json_str = '{"test":"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"}';
$array = json_decode($json_str, True);
unset($json_str);
unset($array);
echo 'after unset args: ' . memory_get_usage() . PHP_EOL;
echo PHP_EOL;
echo 'before unserialize: ' . memory_get_usage() . PHP_EOL;
$serialize_str = 'a:1:{s:4:"test";s:1024:"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";}';
$array = unserialize($serialize_str);
unset($serialize_str);
unset($array);
echo 'after unset args: ' . memory_get_usage() . PHP_EOL;
[root@chengqm test]# php-swoole test.php
before decode_json: 627504
after unset args: 627504
before unserialize: 627504
after unset args: 627536
结果发现,unserialize后确实有一点内存没有释放(后来发现,是安装的 PHP 有问题)
然后就是测试 file_get_contents
对内存的影响
<?php
echo PHP_EOL;
echo 'before get file: ' . memory_get_usage() . PHP_EOL;
$serialize_str = file_get_contents('./serialize_str');
unset($serialize_str);
system('sync && echo 3 > /proc/sys/vm/drop_caches');
echo 'after unset args: ' . memory_get_usage() . PHP_EOL;
[root@chengqm test]# php-swoole test.php
before get file: 624304
after unset args: 624416
结果发现, file_get_contents 也会造成内存增长
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
valgrind
跑了下,应该不算是内存泄漏跑这个也是两次都不一样,第三次就一样了……