PHP 常驻任务不会释放内存的吗?

2019-12-19 15:07:47 +08:00
 raysonlu

写了个处理 redis 阻塞队列的脚本任务常驻在系统里面,随着处理的任务数越多,进程占用内存慢慢增大。脚本大致内容如下:

<?php 

$redis = new Redis();
$redis->setOption(\Redis::OPT_READ_TIMEOUT, -1)

//连接 redis 省略

while(1){
	$data = $redis->brpop('queueName',60);
    
    if(!empty($data)){
    	$obj = new someObj();
        $obj->handleSomething($data);
        unset($obj);
    }else{
    	sleep(10);
    }
}

具体查看进程占用内存,我是参考这些参数: ps auxf命令的 RSS 列,以及 top命令的 RES 列

为什么会这样,按我目前理解,每处理一个任务应该都释放部分内存啊,至少看不到会导致占用内存累加的部分,非常疑惑。请教一下各位 dalao 们。是我用的框架有问题?还是 php 的 redis 扩展问题?

爆了设定的占用内存限制会自动结束进程,设置无限内存也有点实际,这问题有点头疼

10675 次点击
所在节点    PHP
61 条回复
PainfulJoe
2019-12-20 11:11:15 +08:00
全部代码贴出来看看,我试验了半天都没出现内存泄漏
widdy
2019-12-20 12:26:22 +08:00
@jimmzhou 改代码,复用对象。
realpg
2019-12-20 13:20:32 +08:00
@raysonlu #16
写常驻项目 就自己注意释放不用资源
jimmzhou
2019-12-20 14:20:37 +08:00
@widdy 看 34 楼评论 如果 pop 出来的类都不一样 只能在循环里 new 了
raysonlu
2019-12-20 17:41:32 +08:00
感谢大家的回复,我会收纳大家的意见再尝试找出原因!


@haiyang416 @fuxkcsdn @liuxu
设定一定的条件自动重启整个脚本进程,这个方法肯定没毛病,但这么粗暴的做法有影响对 php 的信仰啊


@GGGG430 @JaguarJack @ferock @flashrick @widdy
目前在我的实际代码里,someObj()的确可以复用,我会考虑试试,但如果遇到无法复用的情况,那岂不是又要考究这个问题?


@cabing
你贴的码的主要目的是把 new 放在 while 外面来解决这个问题?我这边连接 redis 可以选择持续连接


@iyaozhen
我的理解是,handleSomething 是对象的函数,函数结束就得释放该函数所占用的内存


@DavidNineRoc
关于释放内存,是$var=null 还是 unset($var),我也有探究过,php 的内存管理准则是对象没有被引用,就得乖乖地准备被 gc 清走,我用过 xdebug 调试过两种方法都能使被引用的对象的引用次数变为 0,然后我个人觉得两者应该是一样


@namek
我会持续关注此问题,不会烂尾贴 hhhh


@luoyou1014
确认线上、本地环境都有开,phpinfo 中 zend.enable_gc 为 on


@fancy111
brpop()超时后的确是返回空数组,empty(array())的确是 true,这没毛病

@shadowsll @realpg
也有看到我释放变量吧(unset $obj),除了$obj 需要释放外,其他变量不需要释放,感谢你分享的经验,我试了一下,我这个框架的日志是实时写到日志文件,框架 phalcon


@liuxu
php 7.2.3, php-redis 4.1.0


@sagaxu
有这部分扩展的黑名单不?


@back0893
cron 执行的话,处理有些场景不实时,甚至要考虑上一个任务是否执行完毕


@PainfulJoe
跟你说个鬼故事,我本地模拟线上测试环境进行轻量测试也是正常,看到占用内存会在处理任务后自己降下来,我也是一脸懵逼才上来探讨探讨

再次感谢关注此问题的各位以及回复的 v 友!
realpg
2019-12-20 18:03:37 +08:00
@raysonlu #45
抱歉 你的代码是用 code 了的
我的移动端之前出了问题 那部分全没看见 所以我并不知道你这里贴了代码……
realpg
2019-12-20 18:05:18 +08:00
new someObj();

someObj 里面的东西如果有未释放内存,不一定会因为你 unset 了这个 obj 的实例而释放。尤其是比较复杂的类型成员变量以及方法。
yoshiyuki
2019-12-20 18:06:12 +08:00
应该主动退出,然后重启一下
Varobjs
2019-12-20 19:53:25 +08:00
昨天也遇到这个问题,现在已经解决

php 垃圾回收 基本还是引用计数的方式,unset 或者 赋值 null 引用计数 = 0,但 php 并不会立即回收当前占用的内存空间,而是 按概率 好像默认百分之一的概率来回收,或者在脚本退出时 释放。

fpm 模式一般很快就执行完,遇到问题的大多是脚本,执行很久,循环很多次的操作,所以内存会一直增加,直到达到默认 128 m 限制

解决方法上面有人说了,就是脚本 先 gc-disable,循环内部结束后 unset 大的类或者数后,调用 gc-collect-cycles 会强制回收计数等于 0 的 内存空间

可能 提高 ini 配置的 垃圾回收概率 也可能解决,不过还没有去验证过
jenschen
2019-12-20 19:58:52 +08:00
我记得,php 在修改变量和函数返回的时候才会触发垃圾回收。
Varobjs
2019-12-20 19:58:54 +08:00
另外,php 是默认开启 垃圾回收的


我是在同步 巨多数据,比如 上千次接口请求,然后 插入数据库 几十万条,但每次循环后,都 unset 了所以变量,或者 赋值 null 了
Varobjs
2019-12-20 20:01:07 +08:00
@jenschen 不是 ,是在引用计数 = 0 触发,但不是每次都触发,
可以搜索 ini 配置 关于 gc 的,有个概率设置。
Varobjs
2019-12-20 20:19:23 +08:00
还有,加入你的代码,真的有循环引用,以上方法也救不了你的
可以 memory-get-usage 写入到日志中,如果加入手动释放逻辑,内存还是单调递增,那就是有循环引用了
jenschen
2019-12-20 20:28:09 +08:00
@Varobjs - -,当变量改变的时候,recount 是不是会成零。函数返回时,变量的引用计数会减 1。好像想把垃圾或者疑似垃圾添加到垃圾回收器。垃圾回收满了或者好像还有一定时间?。去执行垃圾回收。垃圾回收是将所有变量遍历,减一。
Varobjs
2019-12-20 21:02:36 +08:00
@jenschen。。
具体细节我不太了解,php 源码没看过。
最近脚本因为数据多了,频繁出现内存溢出问题,反复确认代码,在变量用完 unset,仍不解决问题后,怀疑垃圾回收的问题,然后在 stackoverflow 搜什么时候执行析构函数时,发现需要手动释放的,另外在内存够用的情况下,关闭 gc 可以很大提高效率,这个其实很好理解。
runtu2019
2019-12-20 22:00:18 +08:00
我用 dnspod 的 api 写了个 ddns 的脚本,里面也用了爬虫框架什么的,cli 运行,用 crontab 定时 10s 执行跑在树莓派里,也没有见内存问题,稳稳的。
我觉得是你思路问题。我这里的业务也遇到过需要常驻刷新任务的需求,但也不会像你一样把一个请求执行卡着,解决方案是用 python 脚本定时执行请求 php 的 url 执行刷新操作,python 一直 while 循环半年了也没出什么问题。
back0893
2019-12-21 01:40:12 +08:00
要不 fork 子进程?
子进程执行就退出,父进程只管子进程生成.
jenschen
2019-12-21 13:23:37 +08:00
@Varobjs 就事论事吧。比方说,脚本一秒执行一次。可能这个脚本执行需要 1-2 分钟。这也会造成内存问题。关闭 gc 是会提高性能。不是说在内存足够下关闭 gc,是在确保不出现循环引用的情况下。
fancy111
2019-12-23 11:11:34 +08:00
给你个建议吧,用 Swoole Tracker 调试一下看看,到底哪里内存泄露了。完了给帖子做个结论。
raysonlu
2019-12-25 23:31:51 +08:00
已结案,维护了一次 php 的信仰(狗头 具体看追加附言

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/630530

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX