Doctrine flush更改并释放内存

时间:2017-06-07 15:14:59

标签: php symfony memory memory-management doctrine-orm

我在使用内存限制较低的Symfony项目时遇到问题。我需要创建几个实体,将它们添加到另一个实体(实体关联),然后刷新对数据库的更改。这发生在while循环中。

问题是有时循环无法完成整个循环,因为进程因内存耗尽而崩溃。当然我不能提高内存限制。

我试着用一些代码更好地解释你......

实体结构

class Device
{
    /**
     * @ORM\ManyToMany(targetEntity="Resource", inversedBy="devices",cascade={"persist", "refresh"}, fetch="EXTRA_LAZY")
     */
    protected $resources;

    public function addResource(Resource $resource)
    {
        if ($this->resources->contains($resource)) return;
        $this->resources->add($resource);
        $resource->addDevice($this);
    }
}

class Resource
{
    /**
     * @ORM\ManyToMany(targetEntity="Device", mappedBy="resources")
     */
    protected $devices;

    public function addDevice(Device $device)
    {
        if ($this->devices->contains($device)) return;
        $this->devices->add($device);
        $device->addResource($this);
    }
}

循环

function doIt(Device $device) {
    while(...) {
        $res = new Resource(...);
        $device->addResource($res); // store $res in memory until end
    }
    $em->persist($device);
    $em->flush();
}

所以问题是在循环结束之前,$device会保留在内存Resource对象中,有时会达到内存限制。

到目前为止我尝试了什么

function doIt(Device $device) {
   $i = 0;
   while(...) {
       $res = new Resource(...);
       $device->addResource($res);
       $i++;
       if ($i % 100 == 0) {
              $em->persist($device);
              $em->flush($device);
              $device->setResources(null); // free up Resources in memory
              $em->refresh($device); // Resources are not stored in memory
       }
   }
   $em->persist($device);
   $em->flush();
}

即使因为无论如何我都看到记忆提升(这可能是由Doctrine引起的),这种效果并不好。此外,它们之间有很多实体和几个关联,并且在数据库中检查结果会给我一些错误(例如实体未被保留)。

你会做什么?

2 个答案:

答案 0 :(得分:1)

您可以尝试一些改善这种情况的事情:

在导入的设置阶段禁用doctrine SQL日志记录机制

$this->getContainer()->get('doctrine')->getConnection()->getConfiguration()->setSQLLogger(null);

尝试定期调用清除(我在处理和刷新一批项目后执行此操作),但之前请阅读文档,因为根据您的代码可能会产生副作用

$this->entityManager->clear();

您似乎已经清除了所有未使用的对象和变量,您也可以尝试在php中调用手动gc_collect_cycle

gc_collect_cycles();

如果使用symfony命令执行导入,请确保使用--no-debug标志启动它

在我的项目中使用导入命令工作得很好,尽管它没有实现完全的内存中立性,但剩余的泄漏可以忽略不计。 也许这对你的情况有帮助。

答案 1 :(得分:0)

我在冲洗后永远不会坚持超过50个实体。尝试将$ i减少到50或更少。也许这有帮助。