gpt4 book ai didi

symfony - 教义 : Why can't I free memory when accessing entities through an association?

转载 作者:行者123 更新时间:2023-12-02 14:07:38 27 4
gpt4 key购买 nike

我有一个ApplicationApplicationFile 有关系:

/**
* @ORM\OneToMany(
* targetEntity="AppBundle\Entity\ApplicationFile",
* mappedBy="application",
* cascade={"remove"},
* orphanRemoval=true
* )
*/
private $files;

文件实体有一个存储二进制数据的字段,大小最大可达 2MB。当迭代大量应用程序及其文件时,PHP 内存使用量会增加。我想把它压低。

我已经尝试过这个:

$applications = $this->em->getRepository('AppBundle:Application')->findAll();
foreach ($applications as $app) {
...
foreach ($app->getFiles() as $file) {
...
$this->em->detach($file);
}
$this->em->detach($app);
}

分离对象应该告诉实体管理器停止关心该对象并取消引用它,但令人惊讶的是它对内存使用量没有影响 - 它不断增加。

相反,我必须手动加载应用程序文件(而不是通过关联方法检索它们),并且内存使用量并没有增加。这有效:

$applications = $this->em->getRepository('AppBundle:Application')->findAll();
foreach ($applications as $app) {
...

$appFiles = $this
->em
->getRepository('AppBundle:ApplicationFile')
->findBy(array('application' => $application));

foreach ($appFiles as $file) {
...
$this->em->detach($file);
}
$this->em->detach($app);
}

我用过xdebug_debug_zval跟踪对 $file 的引用目的。在第一个示例中,某处有一个额外的引用,这解释了为什么内存膨胀 - PHP 无法对其进行垃圾收集!

有谁知道这是为什么吗?这个额外的引用在哪里以及如何删除它?

编辑:明确调用 unset($file)在其循环结束时没有任何效果。此时仍有两个对该对象的引用(用 xdebug_debug_zval 证明)。其中一项包含在 $file 中(我可以取消设置),但还有另一个我无法取消设置的地方。调用$this->em->clear()主循环结束时也没有效果。

编辑 2:解决方案:@origaminal 的答案引导我找到了解决方案,因此我接受了他的答案,而不是提供我自己的答案。

在第一种方法中,我通过 $application 上的关联访问文件。 ,这会产生初始化先前未初始化的 $files 的副作用收藏于$application我在外循环中迭代的对象。

调用$em->detach($application)$em->detach($file)只告诉 Doctrine 的 UOW 停止跟踪对象,但不会影响 $applications 数组我正在迭代,现在已经填充了 $files 的集合这会消耗内存。

我必须取消设置每个 $application对象完成后删除所有对加载的 $files 的引用。为此,我修改了循环:

    $applications = $em->getRepository('AppBundle:Application')->findAll();
$count = count($applications);
for ($i = 0; $i < $count; $i++) {
foreach ($applications[$i]->getFiles() as $file) {
$file->getData();
$em->detach($file);
unset($file);
}
$em->detach($applications[$i]);
unset($applications[$i]);

// Don't NEED to force GC, but doing so helps for testing.
gc_collect_cycles();
}

最佳答案

级联

EntityManager::detach 确实应该删除 Doctrine 对实体的所有引用。但它不会自动对关联实体执行相同的操作。。

您需要通过添加关联的分离选项来级联此操作:

/**
* @ORM\OneToMany(
* targetEntity="AppBundle\Entity\ApplicationFile",
* mappedBy="application",
* cascade={"remove", "detach"},
* orphanRemoval=true
* )
*/
private $files;

现在 $em->detach($app) 应该足以删除对 Application 实体及其关联的 ApplicationFile 的引用实体。

查找与收藏

我非常怀疑通过关联加载 ApplicationFile 实体,而不是使用存储库来findBy() 它们,是问题的根源。

当然,当通过关联加载时,集合将具有对这些子实体的引用。但是当父实体被取消引用时,整个树将被垃圾收集,除非有其他引用这些子实体。

我怀疑您显示的代码是伪/示例代码,而不是生产中的实际代码。请彻底检查该代码以查找其他引用。

清除

有时值得清除整个 EntityManager 并合并一些实体。您可以尝试 $em->clear()$em->clear('AppBundle\Entity\应用程序文件')

清除没有效果

您是说清除 EntityManager 没有效果。这意味着您正在搜索的引用不在(UnitOfWork 的)EntityManager 中,因为您刚刚清除了它。

教义但不是教义

您是否使用任何事件监听器或订阅者?有过滤器吗?有自定义映射类型吗?多个EntityManager?还有什么可以集成到 Doctrine 或其生命周期中,但不一定是 Doctrine 本身的一部分?

尤其是在搜索问题根源时,事件监听器/订阅者经常被忽视。所以我建议你开始看看那里。

关于symfony - 教义 : Why can't I free memory when accessing entities through an association?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31973639/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com