我编写了一个 PHP 插件,可将记录从 Endnote XML 书目文件导入数据库。导入过程涉及几个阶段,其中之一是将尾注记录初始读取到内存中,并为它们创建一个内部的、基于对象的表示。其次,必须扫描所有要导入的记录,以查看其作者、出版物、关键字等是否在数据库中已经有相应的记录。
我在 OS X 10.8.2 上运行 PHP 5.4.7(64 位)。
为了快速完成这些任务,我将几乎所有的数据存储在内存中,而不是将数据写入数据库或反复查询数据库……所有必要的数据都一次读入并根据需要进行查询。
这当然是内存密集型的。但是,我已经制定了许多减少内存占用的策略,这些策略在减少使用的内存量方面非常有效。特别是,我广泛使用原生 PHP 序列化/反序列化工具以及 zlib 来压缩序列化表示。尽管如此,内存使用率仍然高得令人不安,仅导入 500 条 Endnote 记录后就耗尽了最大内存。
为了解决这个问题,我尝试使用unset()
内部函数来释放我不再需要的所有变量、数组和对象,一旦我完成了它们。其中一些对象在实例化时非常大,这就是我尽快处理它们的原因。但是,在进行了一些内存使用分析之后,我发现报告的内存使用情况memory_get_usage(true)
并没有下降,尽管有unset
变量,启用垃圾收集gc_enable()
并通过gc_collect_cycles()
.
我已经阅读了其他帖子,这些帖子表明只要特定变量的引用计数没有下降到零,PHP 就不会释放相关的内存,这是我理解的。我设计了我的代码以避免循环引用......每个不同的内存消耗对象都有一组独立的内部存储数组,它们都不与其他对象共享数据。因此,在销毁宿主对象后,理论上,应该立即释放其所有私有数据。但是,我没有看到这种情况发生。
如果有人想查看我的代码,可以在Github上找到。
1.在文件中找到了对各种高内存使用对象进行测试的主要单元测试,并测量内存使用情况(处理 500 条 Endnote 记录,总共使用 122MB)/test/ObjectStoreTest.php
2.解析 Endnote 数据并将其转换为基于对象的表示的例程(在运行期间使用大约 15MB)在/controller/ParseAndStoreEndnoteRecordsHandler.class.php
3.发现主库已有作者的类(好像用了30MB左右)在/model/resolvers/CreatorExternalReferenceResolver.class.php
我提供这些信息以供参考,以防需要它来回答问题......显然,我不希望任何人花半天时间来分析我的代码。但是,希望这些信息足以清楚地说明我遇到的特定内存使用问题。