php - 遍历对象图时内存泄漏
问题描述
在教义中遍历对象图是否可以很好地扩展?
考虑这个类图实体(保证无环):
/**
* @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 内存,仅此而已。所以对我来说,清理似乎真的没有帮助,以某种方式释放处理过的对象确实失败了。
解决方案
我找到了答案,部分在这里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
and SmallNode extends Node
),并且我的关联被定义为基类Node
。
根据教义文档,在这种情况下,不可能只实例化一个未初始化的代理,所有的孩子都必须被获取。
该死。
推荐阅读
- sql - 在按天分组的时间间隔内计算小时数
- r - 将坐标数据框绘制到基于组的路线中
- reactjs - 如何在 tsx react 中使用 npm/yarn
- ansible - Ansible 循环中断条件
- node.js - 如何从 mongodb 获取动态创建的模式模型的数据
- python - 根据句子中的文本创建变量名
- java - 使用 Java 在 CalendarDateRangePicker 上启用 XML 属性
- azure-cosmosdb - 是否可以在 Cosmos DB Gremlin API 中执行不区分大小写的搜索?
- algorithm - 通过访问一组节点从源到目的地的最短路径
- sql - T-SQL 根据 ID 将行转置为列