我有一个脚本,它将大约150万行(大约400mb的数据)从一个表传输到另一个表(在此过程中,一些数据被转换,修改并放置在正确的字段中)。它是一个简单的脚本,它只是递归加载数据,然后将它放在正确的字段和格式下的新表中。这些脚本通过(作为示例)从表中拉出所有用户然后开始循环遍历用户,将它们插入到新表中,然后从该用户拉出所有帖子,循环并将它们插入到正确的表中然后从帖子中拉出所有评论并插入这些评论,然后跳回来并拉动该用户的所有联系人,最后到下一个用户进行相同的过程。
我只是在传输大量数据时遇到问题,因为它太大而且除了垃圾收集(我知道)之外没有任何类型的内存管理,我无法完成脚本(它在大约200MB内存之前通过大约15,000个连接和项目传输)。
这是一次性的事情,所以我在我的本地计算机上做,而不是实际的服务器。
由于unset()实际上没有释放内存,有没有其他方法来释放变量中的数据?我试图做的一件事是将变量覆盖为NULL值,但这似乎没有帮助。
任何建议都很棒,因为男人,这很臭。
答案 0 :(得分:5)
如果你实际上是递归地做这个,那那就是你的问题 - 你应该迭代地这样做。每次进行下一次调用时,递归处理会留下开销(+垃圾) - 所以最终你达到了极限。迭代方法没有这样的问题,应该积极地进行垃圾收集。
你也在谈论一个令人讨厌的连接数量 - 为什么这么多?我想我并不完全理解你的过程,为什么这种方法是需要的,而不是一个检索连接和一个商店连接。即使您 - 比如说 - 重新连接每一行,您应该考虑使用持久连接,这允许第二次连接到同一个数据库以重用最后一个连接。对于具有多个用户的Web应用程序而言,持久连接不是一个好主意(出于可伸缩性的原因),但在非常有针对性的情况下,它们应该没问题。
答案 1 :(得分:1)
unset()
会释放内存,但前提是您取消设置的对象没有指向它的其他引用。由于PHP使用引用计数而不是“真正的”GC,如果你在某处有循环引用,这可能会咬你 - 一个典型的罪魁祸首是在ORM中,你经常有一个Database
对象,它包含对某些{{1}的引用对象,每个Table
对象都有一个返回Table
的引用。即使两个对象都没有外部引用,它们仍然相互引用,防止引用计数达到零。
另外,两个表都在同一个数据库中吗?如果是这样,您所需要的只是一个简单的Database
查询,映射列并在运行中进行一些转换(尽管您需要执行的处理在SQL中可能不可行或不可行。)
除此之外,您不需要那么多连接。只为读者打开一个,为作者打开一个;在编写器上准备一个语句,执行读者查询,一次获取一行(这很重要:不要一次性获取所有这些)来自阅读器查询,进行处理,将其填入准备好的编写器语句中,冲洗并重复。在前几行之后,PHP的内存使用量应保持大致不变。