
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 apache/php-fpm/swoole 应该都有一个叫 max_request 的参数,执行一定量请求后重启进程,哪怕代码有内存泄漏也会还给系统 |
6 6ufq0VLZn0DDkL80 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 |