5

这是一个适合你们任何 Doctrine 用户的。我有一个 PHP CLI 守护进程,它每 n 秒检查一次表以查找尚未处理的条目。它基本上是一个FIFO。无论如何,我总是超过分配给 PHP 的内存,因为 Doctrine 并没有释放它的资源。为了解决这个问题,它免费提供了查询对象。我似乎无法让它工作。这是代码:

 22     print "You are using " . (memory_get_usage() / 1024). "\n";
 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 . "\n";
 30     $query->free();

任何想法我做错了什么?

编辑:我正在使用 1.0.3

编辑:我已经尝试了以下所有建议。我非常有希望,unset()因为在我找到它之前我就在那里free()

这是更多可能有助于任何帮助的代码。在您质疑连接的打开和关闭之前,它将是生成子进程的守护进程,并且根据我的经验,连接必须是唯一的。

  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) . "\n";
 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 . "]\n";
 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
4

5 回答 5

6

问题是,这free()并没有从内存中删除 Doctrine 对象,而只是消除了对这些对象的循环引用,从而使垃圾收集器可以清理这些对象。请参阅Doctrine 手册中的23.6 自由对象

从 5.2.5 版本开始,PHP 不能对具有循环引用的对象图进行垃圾收集,例如,Parent 具有对 Child 的引用,而 Child 具有对 Parent 的引用。由于许多学说模型对象都有这样的关系,即使对象超出范围,PHP 也不会释放它们的内存。

对于大多数 PHP 应用程序来说,这个问题并不重要,因为 PHP 脚本往往是短暂的。寿命较长的脚本,例如批量数据导入器和导出器,可能会耗尽内存,除非您手动中断循环引用链。Doctrine 在 Doctrine_Record、Doctrine_Collection 和 Doctrine_Query 上提供了一个 free() 函数,它消除了对这些对象的循环引用,将它们释放用于垃圾回收。

解决方案应该是使用后unset()$query对象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 . "\n";
$query->free();
unset($query); // perhaps $query = null; will also work
于 2008-11-17T19:01:17.023 回答
1

Doctrine_Query 也有一个 free() 方法,此时您只是在 Doctrine_Collection 上调用 free(),例如,尝试:

 $query = Doctrine_Query::create()
             ->from('SubmissionQueue s')
             ->where('s.time_acted_on IS NULL')
             ->orderby('s.time_queued')
             ->limit(1);
 $results = $query->execute();
 print $results[0]->time_queued . "\n";

 $results->free();
 $query->free();
于 2009-02-16T23:43:33.223 回答
0

没有使用 Doctrine 的经验(只是我在这个周末发现了一些兴趣......),所以接受或留下我的猜测...... ^_^

我会尝试将查询创建与其执行部分分开:

$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 . "\n";
$query->free();

不确定执行返回什么,但以防万一,值得尝试......除非有人有更开明的建议!:-P

于 2008-11-17T15:55:14.340 回答
0

试试 $query->free(true);

(?)

于 2008-11-17T16:06:14.880 回答
0

我想我可能只是将 PDO 用于实际上不需要 ORM 的后端部分,因为没有那么多查询。我真的很想在这个系统中的所有应用程序中使用一种单一的方式与数据库进行交互。也许我会多考虑一下。

于 2008-11-18T19:41:24.960 回答