我在使用symfony 1.4和doctrine 1.2将对象批量插入数据库时遇到问题。
我的模型有一种称为“扇区”的对象,每个对象都有几个“Cupo”类型的对象(通常范围从50到200000)。这些物体非常小;只是一个短标识符字符串和一个或两个整数。每当用户创建一组扇区时,我需要自动将所有这些“Cupo”实例添加到数据库中。如果出现任何问题,我正在使用一个学说交易来回滚所有内容。问题是我只能在php耗尽内存之前创建大约2000个实例。它目前有128MB的限制,应该足以处理使用少于100个字节的对象。我已经尝试将内存限制增加到512MB,但是php仍然崩溃,但这并没有解决问题。我正确地进行批量插入还是有更好的方法?
这是错误:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes) in /Users/yo/Sites/grifoo/lib/vendor/symfony/lib/log/sfVarLogger.class.php on line 170
这是代码:
public function save($conn=null){
$conn=$conn?$conn:Doctrine_Manager::connection();
$conn->beginTransaction();
try {
$evento=$this->object;
foreach($evento->getSectores() as $s){
for($j=0;$j<$s->getCapacity();$j++){
$cupo=new Cupo();
$cupo->setActivo($s->getActivo());
$cupo->setEventoId($s->getEventoId());
$cupo->setNombre($j);
$cupo->setSector($s);
$cupo->save();
}
}
$conn->commit();
return;
}
catch (Exception $e) {
$conn->rollback();
throw $e;
}
再次,此代码适用于少于1000个对象,但任何大于1500的代码都会失败。谢谢你的帮助。
答案 0 :(得分:33)
尝试做
$cupo->save();
$cupo->free();
$cupo = null;
(但代替我的代码)而且我仍然会得到内存溢出。还有其他想法吗?
<强>更新强>
我在databases.yml中创建了一个新环境,如下所示:
all:
doctrine:
class: sfDoctrineDatabase
param:
dsn: 'mysql:host=localhost;dbname=.......'
username: .....
password: .....
profiler: false
profiler:false 条目会禁用doctrine的查询日志记录,通常会保留您进行的每个查询的副本。它并没有阻止内存泄漏,但是通过我的数据导入,我能够获得大约两倍的内存泄漏。
更新2
我添加了
Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true );
在运行我的查询之前,并更改了
$cupo = null;
到
unset($cupo);
现在,我的剧本一直快乐地流着。我很确定它会在没有耗尽RAM的情况下完成。
更新3
烨。这是获胜的组合。
答案 1 :(得分:3)
我刚刚使用symfony 1.4执行了“daemonized”脚本,并设置以下内容停止了内存占用:
sfConfig::set('sf_debug', false);
答案 2 :(得分:3)
对于symfony任务,我也遇到了这个问题,并完成了以下事情。它对我有用。
禁用调试模式。在db connection initialize
之前添加以下内容sfConfig::set('sf_debug', false);
为数据库连接设置自动查询对象的免费属性
$connection->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true );
使用后释放所有对象
$object_name->free()
使用unset($array_name)
$q->free()
(对于任何使用查询的时间,这都是一个很好的做法。)这就是全部。希望它可以帮助某人。
答案 3 :(得分:2)
学说泄漏,你无能为力。确保在适用时使用$ q-&gt; free()以最小化效果。 Doctrine不适用于维护脚本。解决此问题的唯一方法是将脚本分解为将执行部分任务的部分。一种方法是在脚本中添加一个start参数,在处理完一定数量的对象后,脚本会以更高的起始值重定向到自身。这对我来说很有效,尽管它使编写维护脚本变得更加麻烦。
答案 4 :(得分:1)
每次保存后尝试unset($cupo);
。这应该是有帮助的。另一件事是拆分脚本并进行一些批处理。
答案 5 :(得分:1)
答案 6 :(得分:1)
对我来说,我刚刚初始化了这样的任务:
// initialize the database connection
$databaseManager = new sfDatabaseManager($this->configuration);
$connection = $databaseManager->getDatabase($options['connection'])->getConnection();
$config = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', true);
sfContext::createInstance($config);
(WITH PROD CONFIG)
并在doctrine对象
记忆稳定在25Mo
memory_get_usage=26.884071350098Mo
使用php 5.3 on debian squeeze
答案 7 :(得分:0)
定期关闭并重新打开连接 - 不确定原因,但似乎PDO保留了引用。
答案 8 :(得分:0)
对我有用的是调用free
这样的方法:
$cupo->save();
$cupo->free(true); // free also the related components
unset($cupo);