phper 们应该都会自动内存泄露主要由于循环应用导致的,比如如下代码将会导致内存泄露:
function fun1()
{
$a = ['hello'];
$a[] = &$a;
}
func1();
自己的代码还好,可以检查检查,由于使用了第三方依赖,怎么在依赖的文件中定位到有这种有内存泄露的代码呢?小弟实在想不出有什么好的办法
上面的示例代码不是特别好,请看下面:
<?php
function fun1()
{
$a = ['hello'];
$a[] = &$a;
}
while(true) {
fun1();
echo memory_get_usage() . "\n";
sleep(1);
}
有兴趣的朋友可以试试上面的代码,内存将会不断增加(centos7 php7.4)
➔ /usr/local/opt/[email protected]/bin/php a.php
1230440
1230880
1231288
1231696
1232104
1232512
1232920
1233328
1233736
1
leven87 2020-08-13 18:41:01 +08:00
memory_get_usage ? 不懂
知名一些的第三方应用,都有 github 或者论坛吧。 |
2
sagaxu 2020-08-13 18:43:58 +08:00 via Android
循环引用不会导致内存泄露
|
4
ben1024 2020-08-13 19:19:09 +08:00
xdebug 监听函数 memory_get_usage(true)/1024/1024/8 的内存值?
|
5
wangritian 2020-08-13 19:28:11 +08:00 1
apache/php-fpm/swoole 应该都有一个叫 max_request 的参数,执行一定量请求后重启进程,哪怕代码有内存泄漏也会还给系统
|
6
cholerae 2020-08-13 19:44:03 +08:00
不懂 php,不过搜了一下看 php 5.3 开始就有能回收环的 gc 了,为啥这个代码会内存泄漏?
|
7
JJstyle OP @wangritian 是一段脚本,在 cli 下运行的,其实我只是讨论一个方法,毕竟我可以发现当内存达到一定量时退出,rnhou 让 supervisor 帮我重启
|
9
JJstyle OP @cholerae 我看了一下 php 的文档,大概是 php5.3 后,只有当根缓冲区满了才会 清除循环引用产生的垃圾
|
10
superwhite 2020-08-13 20:21:06 +08:00
php7.2 win,PHP7.3 centOs,试了你的代码,不会内存泄露
|
11
CismonX 2020-08-13 21:31:06 +08:00
在 PHP 的 debug build 中,PHP 进程退出时 Zend MM 会打印出未释放的内存的相关信息(仅限那些用 emalloc 系列函数分配的由 Zend MM 管理的内存),包括其地址、分配这块内存的相关函数等
当然,实际调试的时候这些信息可能不够,需要 valgrind 。 |
12
wangbenjun5 2020-08-13 21:33:01 +08:00
@wangritian 正解,除非写常驻进程的应用,不然不用操心内存泄露问题,如果要写常驻进程应用,为何不用 go
|
13
JJstyle OP @wangbenjun5 帮朋友维护一个个人项目,恰好我对 php 熟悉
|
14
zjsxwc 2020-08-14 08:23:09 +08:00
看来只能手动 gc 了
1 <?php 2 3 4 function fun1() 5 { 6 $a = ['hello']; 7 $a[] = &$a; 8 } 9 10 while(true) { 11 fun1(); 12 gc_collect_cycles(); 13 echo memory_get_usage() . "\n"; 14 sleep(1); 15 } |
15
zjsxwc 2020-08-14 08:40:24 +08:00
php 碰到内存“泄露”问题,有几个方面
1. “全局变量” 或者 “常驻依赖注入容器对象” 的膨胀导致内存不够,比如 orm 中 EntityManager 没有及时 clear 追踪的不再被使用的数据库实体对象。 2. 代码逻辑“死循环” 导致内存不够。 3. 使用了存在内存泄露 bug 的 c/c++拓展。 当接楼上我的回答,当 php 内存达到设置值时,比如 32M 时会自动触发垃圾回收,所以没有必要手动 gc_collect_cycles(); php 7.3 之后有个 gc_status();可以看 gc 状态 ``` zjsxwc@zjsxwc-PC:~$ cat 2.php <?php function fun1() { $a = ['hello']; $a[] = &$a; } while(true) { var_dump(gc_status()); fun1(); var_dump(gc_status()); gc_collect_cycles(); echo memory_get_usage() . "\n"; sleep(1); } zjsxwc@zjsxwc-PC:~$ '/home/zjsxwc/php74/bin/php' 2.php array(4) { ["runs"]=> int(0) ["collected"]=> int(0) ["threshold"]=> int(10001) ["roots"]=> int(0) } array(4) { ["runs"]=> int(0) ["collected"]=> int(0) ["threshold"]=> int(10001) ["roots"]=> int(1) } 365496 array(4) { ["runs"]=> int(1) ["collected"]=> int(1) ["threshold"]=> int(10001) ["roots"]=> int(0) } array(4) { ["runs"]=> int(1) ["collected"]=> int(1) ["threshold"]=> int(10001) ["roots"]=> int(1) } 365496 ``` |
16
wangritian 2020-08-14 09:34:53 +08:00
@wangbenjun5 +1 我也是 web 项目用 php-swoole,小工具或者中间件用 go/python
|
17
gouchaoer2 2020-08-14 11:08:03 +08:00
php 有检测循环引用的机制,只是内存涨到一定大小才会触发
|
18
jimduan 2020-08-14 18:19:31 +08:00
php5.3 后的 gc, 已经自动帮我们解决了!
只需要更多的关注, 业务场景中是否一次性拉取过多的数据进行计算导致 OOM ;常驻内存脚本是否请求了很多资源没有释放 PHP 的垃圾回收机制-理解 PHP 如何解决循环引用导致的内存泄漏问题 http://blog.100dos.com/2017/04/07/php-garbage-collection-collect-cycles/ 请手动释放你的资源(Please release resources manually) https://www.laruence.com/2012/07/25/2662.html |