我在使用内存限制较低的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引起的),这种效果并不好。此外,它们之间有很多实体和几个关联,并且在数据库中检查结果会给我一些错误(例如实体未被保留)。
你会做什么?
答案 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或更少。也许这有帮助。