为什么 PHP Doctine 的 free() 不起作用?
这是给你们任何 Doctrine 用户的.我有一个 PHP CLI 守护进程,它每 n 秒检查一次表以查找尚未处理的条目.它基本上是一个FIFO.无论如何,我总是超过分配给 PHP 的内存,因为 Doctrine 并没有释放它的资源.为了解决这个问题,它免费提供了查询对象.我似乎无法让它工作.代码如下:
This is one is for any of you Doctrine users out there. I have a PHP CLI daemon process that checks a table every n seconds to find entries that haven't been processed. It's basically a FIFO. Anyways, I always exceed the memory allocated to PHP becuase Doctrine does not free it's resources. To combat this problem it provides free for the query object. I can't seem to make it work though. Here's the code:
22 print "You are using " . (memory_get_usage() / 1024). "
";
23 $query = Doctrine_Query::create()
24 ->from('SubmissionQueue s')
25 ->where('s.time_acted_on IS NULL')
26 ->orderby('s.time_queued')
27 ->limit(1)
28 ->execute();
29 print $query[0]->time_queued . "
";
30 $query->free();
任何想法我做错了什么?
Any ideas what I am doing wrong?
我使用的是 1.0.3
I am using 1.0.3
我已经尝试了以下所有建议.我对 unset()
非常有希望,因为我在找到 free()
之前就已经在里面了.
I have tried all of the below suggestions. I was very hopeful for unset()
as I had it in there before I found free()
.
这里有更多可能有助于任何帮助的代码.在您质疑连接的打开和关闭之前,它将是生成子进程的守护进程,并且根据我的经验,连接必须是唯一的.
Here is more of the code to possibly aid in any help. Before you question the opening and closing of the connection it will be daemon process that spawns children and from I have experienced the connection has to be unique.
1 <?php
2
3 require_once('/usr/local/lib/php/Doctrine/lib/Doctrine.php');
4
5 spl_autoload_register(array('Doctrine', 'autoload'));
6
7 $manager = Doctrine_Manager::getInstance();
8 $manager->setAttribute('model_loading','conservative');
9 Doctrine::loadModels('lib/model/master');
10
11 while(1){
12 print "You are using " . intval(memory_get_usage() / 1024) . "
";
13 $manager->connection('********************************************','master');
14 $query = Doctrine_Query::create()
15 ->from('SubmissionQueue s')
16 ->where('s.time_acted_on IS NULL')
17 ->orderby('s.time_queued')
18 ->limit(1)
19 ->execute();
20 print "[" . $query[0]->time_queued . "]
";
21 $query->free();
22 unset($query);
23 $query = null;
24 $manager->closeConnection(Doctrine_Manager::getInstance()->getConnection('master'));
25 sleep(5);
26 }
27
一些示例输出:
You are using 14949KB
[2008-11-17 13:59:00]
You are using 14978KB
[2008-11-17 13:59:00]
You are using 15007KB
[2008-11-17 13:59:00]
You are using 15035KB
[2008-11-17 13:59:00]
You are using 15064KB
[2008-11-17 13:59:00]
You are using 15093KB
[2008-11-17 13:59:00]
You are using 15121KB
[2008-11-17 13:59:00]
You are using 15150KB
[2008-11-17 13:59:00]
You are using 15179KB
[2008-11-17 13:59:00]
You are using 15207KB
[2008-11-17 13:59:00]
You are using 15236KB
[2008-11-17 13:59:00]
You are using 15265KB
[2008-11-17 13:59:00]
You are using 15293KB
[2008-11-17 13:59:00]
You are using 15322KB
推荐答案
问题是,free()
并没有从内存中删除 Doctrine 对象,只是消除了这些对象上的循环引用,使垃圾收集器可以清理这些对象.请参阅23.6 自由对象教义手册:
The problem is, that free()
does not remove the Doctrine objects from memory but just eliminates the circular references on those objects, making it possible for the garbage collector to cleanup those objects. Please see 23.6 Free Objects in the Doctrine manual:
从 5.2.5 版本开始,PHP 不能垃圾收集对象图有循环引用,例如家长有一个 Child 的引用,它有一个参考家长.由于许多教义模型对象有这样的关系,PHP不会释放他们的即使对象用完也能记忆范围.
As of version 5.2.5, PHP is not able to garbage collect object graphs that have circular references, e.g. Parent has a reference to Child which has a reference to Parent. Since many doctrine model objects have such relations, PHP will not free their memory even when the objects go out of scope.
对于大多数 PHP 应用程序,这问题影响不大,因为 PHP 脚本往往是昙花一现.寿命更长的脚本,例如批量数据导入器和出口商,可能会耗尽内存除非你手动打破循环参考链.教义提供了一个Doctrine_Record 上的 free() 函数,Doctrine_Collection 和Doctrine_Query 消除了对这些对象的循环引用,将它们释放为垃圾收藏.
For most PHP applications, this problem is of little consequence, since PHP scripts tend to be short-lived. Longer-lived scripts, e.g. bulk data importers and exporters, can run out of memory unless you manually break the circular reference chains. Doctrine provides a free() function on Doctrine_Record, Doctrine_Collection, and Doctrine_Query which eliminates the circular references on those objects, freeing them up for garbage collection.
解决办法应该是unset()
使用free()
后的$query
对象:
The solution should be to unset()
the $query
object after using free()
:
$query = Doctrine_Query::create()
->from('SubmissionQueue s')
->where('s.time_acted_on IS NULL')
->orderby('s.time_queued')
->limit(1);
$query->execute();
print $query[0]->time_queued . "
";
$query->free();
unset($query); // perhaps $query = null; will also work
相关文章