Memory 每次读取记录时,内存使用量都会增加

Memory 每次读取记录时,内存使用量都会增加,memory,orm,cakephp-3.0,Memory,Orm,Cakephp 3.0,我有几个数据库管理任务,需要遍历数据库中的每个记录。我的理解是,使用CakePHP 3.x ORM,我可以做类似的事情,而且它在内存中一次只能有一条记录: $records = TableRegistry::get('Whatever')->find(); foreach ($records as $record) { // do some processing } 然而,这最终会因“内存不足”异常而崩溃。我已经添加了一点关于内存\u get\u peak\u使用情况的日志记录,

我有几个数据库管理任务,需要遍历数据库中的每个记录。我的理解是,使用CakePHP 3.x ORM,我可以做类似的事情,而且它在内存中一次只能有一条记录:

$records = TableRegistry::get('Whatever')->find();
foreach ($records as $record) {
    // do some processing
}
然而,这最终会因“内存不足”异常而崩溃。我已经添加了一点关于
内存\u get\u peak\u使用情况的日志记录
,并且它随着每次迭代而增加,即使在foreach循环中除了日志记录之外没有其他事情发生。每次通过环路时,增量约为12K

我正在运行3.2.7,无论是否启用调试和/或SQL日志记录,结果都是相似的。向
gc\u collect\u cycles()
添加频繁调用只会减慢进程,对内存使用没有帮助


这是预期的,还是一个bug?如果是前者,我可以在代码中做些什么来防止它?(显然,我可以分批处理,但这不是一个优雅的解决方案。)

据我所知,这是预期的行为,当您开始迭代对象($records)时,使用ORM执行查询构建。因此,所有数据都加载到内存中,然后逐个迭代每个条目


如果你想限制内存的使用,我建议你调查一下。通过这些,您可以提取要处理的子集,从而限制内存使用。

CakePHP 3.x ORM为
ResultSet
对象内置了查询缓存。迭代结果集时,实体存储在内部数组中。这样做是为了可以倒带迭代器并再次循环

如果只对大型结果集迭代一次,并且希望减少内存使用,那么必须禁用结果缓冲

$records = TableRegistry::get('Whatever')->find()->bufferResults(false);
foreach ($records as $record) {
    // do some processing
}
关闭缓冲后,将从结果集中提取实体,之后不应有对该实体的引用

CakePHP手册中提供了此功能的文档:


这里是API参考:

我认为新的ORM在以这种方式使用时一次只能检索一条记录。如果我在结果集上调用
toArray
,那么它肯定会立即加载所有内容,但随着时间的推移,它会不断增加,这一事实似乎表明它没有加载。我认为您混淆了。我不是ORM方面的专家,但我很确定研究ORM将有助于优化您的查询:)此外,我刚刚观看了哪种类型的ORM演示了ORM的威力。可能对您也有用:)如果它一次将所有记录检索到内存中,然后一次一个地遍历它们,它将立即崩溃。(或者,如果我读取一个较小的数字,内存将立即跳转到其峰值使用量,然后相对不变地坐在那里。)内存使用量随着每次迭代不断增加,直到崩溃,这一事实告诉我,它一次只获取一条记录,但在我继续下一条记录时不会处理该对象。这对我来说是非常清楚的;也许我没有解释清楚。你试过关闭吗?@ndm,这听起来很有希望,所以我运行了两个快速测试,但奇怪的是,一些测试似乎显示,随着缓冲功能关闭,内存使用率增加得更快。完全可能是我在考试中做错了什么。。。其他测试崩溃,告诉我“当其他未缓冲的查询处于活动状态时无法执行查询”。在这种特殊情况下,这可能会破坏我的交易。我必须仔细考虑一下,看看是否有一种解决方案比在小批量中运行大查询对代码的干扰更小。