【问题标题】:Leaking memory while traversing an object graph遍历对象图时内存泄漏
【发布时间】:2021-10-11 15:17:31
【问题描述】:

在教义中遍历对象图是否可以扩展?

考虑这个类似图形的实体(保证无环):

/**
  * @ORM\Entity()
  */
class Node {
    //...
    /**
     * @ORM\ManyToOne(targetEntity="Node")
     */
    public $child1;
    /**
     * @ORM\ManyToOne(targetEntity="Node")
     */
    public $child2;
    // ...
}

我正在像这样以迭代方式遍历对象图

$root = $this->em->find(Node::class, '1');
$stack = new Ds\Stack();
$stack->push($root->getId());
while(!$stack->isEmpty()) {
    $node = $em->find(Node::class, $stack->pop());
    work_on($node);
    if($node->child1) $stack->push($node->child1->getId());
    if($node->child2) $stack->push($node->child2->getId());
    $this->em->clear();
    gc_collect_cycles();
}

实际上,我的堆栈大小高达 70.000,我正在遍历大小为 1.000.000 个节点的图。

这就是深度优先搜索。我希望内存消耗保持不变,但它会不断上升,我看到 8 GB 甚至更多。 我很确定不会保留对已处理节点的任何引用。

如果我离开 UoW 清除并在开始时执行预取 $em->getRepository(Node:class)->findAll(),我将获得 13 GB 内存,仅此而已。所以对我来说,清除似乎真的没有帮助,以某种方式释放已处理的对象确实失败了。

【问题讨论】:

    标签: php memory doctrine-orm


    【解决方案1】:

    我找到了答案,部分是在这里https://stackoverflow.com/a/25754165/5330805。 并通过意识到这种情况:

    假设我访问了 root,然后是 A,然后是 B(深度优先搜索)。

    在 root 上工作时,我将 A、D、E、F 和 G 添加到堆栈中。
    G 将被处理得很晚,但已经引用了 A。 所以当我完成 A 时,实际上还有一个对 A 的引用(在 G 中),所以它会留在内存中。

    如果学说只是在 G 中加载了一个指向 A 的代理,这将不是问题,但是:

    事实上,我的实体是一个继承层次结构(例如,BigNode extends Node 和 SmallNode extends Node),我的关联被定义为基类 Node。

    根据doctrine docs,在这种情况下不可能只实例化一个未初始化的代理,所有的孩子都必须被获取。

    该死的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-30
      • 2015-07-03
      • 2011-01-26
      • 2012-10-31
      • 1970-01-01
      • 2012-09-12
      • 1970-01-01
      • 2011-03-05
      相关资源
      最近更新 更多