Jur*_*man 15 php memory garbage-collection command-line-interface beanstalkd
我想使用Zend Framework 2控制器在php中为beanstalkd编写一个worker .它通过CLI启动并将永久运行,从此示例中请求来自beanstalkd的作业.
在简单的伪类代码中:
while (true) {
$data = $beanstalk->reserve();
$class = $data->class;
$params = $data->params;
$job = new $class($params);
$job();
}
Run Code Online (Sandbox Code Playgroud)
在$job这里有一个__invoke()过程的方法.但是,这些工作中的某些事情可能会持续很长时间.有些可能会运行相当大的内存.有些人可能注入了$beanstalk对象,自己开始新的工作,或者有一个Zend\Di\Locator实例从DIC中提取对象.
我很担心这种设置对于在长期的生产环境,为可能的循环引用可能会产生,(此时)我不明确"做"任何垃圾回收,而这个动作可能运行数周/月/年*.
*)在beanstalk中,reserve是一个阻塞调用,如果没有可用的作业,这个worker将等到从beanstalk获得任何响应.
我的问题:php如何长期处理这个问题,我是否应该采取任何特殊的预防措施来防止这种情况发生?
我确实考虑过并且可能会有所帮助(但如果我错了请更正并在可能的情况下添加更多内容):
$job在每次迭代中取消设置__destruct()从a中明确取消引用$job(注意:从这里更新)
我确实用任意工作进行了一些测试.我包括的工作是:"简单",只是设置一个值; "longarray",创建一个包含1,000个值的数组; "producer",让循环注入$pheanstalk并向队列添加三个simplejobs(所以现在有一个从job到beanstalk的引用); "locatoraware",其中Zend\Di\Locator给出了a 并且实例化了所有作业类型(尽管未调用).我在队列中添加了10,000个作业,然后我将所有作业保留在队列中.
"simplejob"的结果(每1000个工作的内存消耗,有memory_get_usage())
0: 56392
1000: 548832
2000: 1074464
3000: 1538656
4000: 2125728
5000: 2598112
6000: 3054112
7000: 3510112
8000: 4228256
9000: 4717024
10000: 5173024
Run Code Online (Sandbox Code Playgroud)
选择随机工作,测量与上述相同.分配:
["Producer"] => int(2431)
["LongArray"] => int(2588)
["LocatorAware"] => int(2526)
["Simple"] => int(2456)
Run Code Online (Sandbox Code Playgroud)
记忆:
0: 66164
1000: 810056
2000: 1569452
3000: 2258036
4000: 3083032
5000: 3791256
6000: 4480028
7000: 5163884
8000: 6107812
9000: 6824320
10000: 7518020
Run Code Online (Sandbox Code Playgroud)
上面的执行代码更新为:
$baseMemory = memory_get_usage();
gc_enable();
for ( $i = 0; $i <= 10000; $i++ ) {
$data = $bheanstalk->reserve();
$class = $data->class;
$params = $data->params;
$job = new $class($params);
$job();
$job = null;
unset($job);
if ( $i % 1000 === 0 ) {
gc_collect_cycles();
echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "<br>";
}
}
Run Code Online (Sandbox Code Playgroud)
正如大家所注意到的那样,内存消耗在php中并未被利用并保持在最低限度,但随着时间的推移而增加.
我最终对当前的代码基准线进行了基准测试,之后我得出了以下结论:
$job = $this->getLocator()->get($data->name, $params);
Run Code Online (Sandbox Code Playgroud)
它使用Zend\Di依赖注入,实例管理器在整个过程中跟踪实例。因此,在调用作业并可以将其删除后,实例管理器仍将其保留在内存中。不立即用于Zend\Di实例化作业会导致静态内存消耗,而不是线性内存消耗。