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

时间:2016-04-25 18:44:03

标签: memory orm cakephp-3.0

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

$records = TableRegistry::get('Whatever')->find();
foreach ($records as $record) {
    // do some processing
}

然而,这最终会因“内存不足”异常而崩溃。我添加了一些memory_get_peak_usage的日志记录,并且每次迭代都会增加,即使除了foreach循环中发生的日志记录之外什么都没有。每次循环时Δ值约为12K。

我正在运行3.2.7,无论是否启用了调试和/或SQL日志记录,结果都是类似的。频繁调用gc_collect_cycles()只会减慢进程速度,但对内存使用没有帮助。

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

2 个答案:

答案 0 :(得分:1)

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

如果您只想迭代一个大型结果集,并且想要减少内存使用量,那么您必须禁用结果缓冲。

$records = TableRegistry::get('Whatever')->find()->bufferResults(false);
foreach ($records as $record) {
    // do some processing
}

关闭缓冲后,实体将从结果集中获取,之后不应该对它进行引用。

CakePHP书中提供了此功能的文档:https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#working-with-result-sets

以下是API参考:https://api.cakephp.org/3.6/class-Cake.Database.Query.html#_bufferResults

答案 1 :(得分:0)

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

如果您想限制内存使用量,建议您查看limitoffset。通过这些,您可以提取要处理的子集,从而限制内存使用。