作者:左伊 | 来源:互联网 | 2024-12-17 18:39
在 Python 环境下,我需要将大量小型 PDF 文件(例如500个单页PDF,每个文件约400KB)有效合并成一个大文件。这些 PDF 文件作为 BytesIO
对象存储在内存中,形成一个列表:
pdf_list = [pdf1_fileobj, pdf2_fileobj, ..., pdfn_fileobj]
这里的每个 pdf_fileobj
都是一个 BytesIO
类型的对象。理论上,这些文件占用的总内存大约为200MB。
然而,在实际操作过程中,我发现即使在执行完合并操作后,程序的内存使用峰值达到了近700MB,远远超过了预期。通过调用 gc.collect()
手动触发垃圾回收,内存使用量可以降低至350MB左右。这引发了一系列疑问:为何需要手动进行垃圾回收?是否存在更有效的内存管理方法?
下面是用于合并 PDF 文件的示例代码:
import PyPDF2
import io
import resource # 用于调试
def merge_pdfs(pdf_files):
''' 在内存中合并 PDF 文件 '''
merger = PyPDF2.PdfFileMerger()
for file in pdf_files:
merger.append(file)
output = io.BytesIO()
merger.write(output)
merger.close()
output.seek(0)
return output
merged_pdf = merge_pdfs(pdf_list)
# 输出最大内存使用情况
print('Memory usage: %s (kB)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
问题总结:
- 上述代码为何需要接近700MB的内存来处理总计200MB的数据?
- 在相关变量超出作用域后,为何还需手动运行垃圾回收以释放内存?
- 使用
BytesIO
和 merger.write(output)
方法是否适合此类场景?
解决方案建议:
- 内存使用过高可能是由于
.append
方法和 merger.write(output)
过程中创建了额外的流对象,导致内存占用翻倍。 - 需要手动运行垃圾回收是因为 PyPDF2 库中存在的内存泄漏问题,某些对象未能被自动回收。
- 为了优化内存使用,可以考虑采用分批处理的方式,即每次合并一部分文件并临时保存至磁盘,随后清空这部分文件的内存占用,继续处理剩余部分。