我在使用 Dompdf 生成 PDF 文件时在 Symfony 应用程序中遇到内存不足问题。我怀疑 Dompdf 库中可能存在内存泄漏。为了进行调查,我编写了一个脚本来创建多个 PDF 文件并监控内存使用情况。
use Dompdf\Dompdf;
ini_set('memory_limit', '20M');
print memory_get_usage() . PHP_EOL;
for ($i = 0; $i < 1000; $i ++) {
print memory_get_usage() . PHP_EOL;
createPDF();
}
print memory_get_usage() . PHP_EOL;
function createPDF () {
// instantiate and use the dompdf class
$dompdf = new Dompdf();
$dompdf->loadHtml('hello world');
// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'landscape');
// Render the HTML as PDF
$dompdf->render();
}
但是,运行此脚本会导致以下错误:
PHP Fatal error: Allowed memory size of 20971520 bytes exhausted (tried to allocate 12288 bytes) in path/to/vendor/dompdf/dompdf/src/Css/Stylesheet.php on line 281
我怀疑 Dompdf 库中可能存在内存泄漏。如何验证该问题是否确实与 Dompdf 有关,或者是否存在其他潜在问题导致内存耗尽?
问题是 PHP 垃圾收集器没有启动。
如果在
gc_collect_cycles()
中添加 createPDF()
,则可以强制进行垃圾回收。
您可以通过以下方式跟踪 GC:
php -dmemory_limit=7M -dxdebug.mode=gcstats -dxdebug.start_with_request=yes min.php
并在 /tmp/ 或您设置 XDebug 输出的任何位置查找
gcstats
文件。
那么为什么垃圾收集器没有启动呢?好吧,按照https://www.php.net/manual/en/features.gc.collecting-cycles.php:
当垃圾收集器打开时,只要根缓冲区满了,就会执行如上所述的循环查找算法。根缓冲区的固定大小为 10,000 个可能的根(尽管您可以通过更改 PHP 源代码中 Zend/zend_gc.c 中的 GC_THRESHOLD_DEFAULT 常量并重新编译 PHP 来更改此设置)。当垃圾收集器关闭时,循环查找算法将永远不会运行。但是,无论垃圾收集机制是否已使用此配置设置激活,可能的根将始终记录在根缓冲区中。
由于 a
DomPdf
实例每次迭代都会占用相当大的内存块(其中很多位于 FontMetrics
缓存中),根缓冲区中没有足够的对象(它是一个小库)来生成 GC在内存耗尽之前。
如果您在
gc_status()
结束时运行 createPdf
,您会发现运行一次后您仅获得约 150 个根(取决于所选的适配器)。对于 20M,您将获得大约 7000 个根,低于 10k 阈值。如果将限制增加到 40M,脚本会成功完成,并且 8 次 GC 运行永远不会耗尽内存:
Garbage Collection Report
version: 1
creator: xdebug 3.2.0 (PHP 8.2.1)
Collected | Efficiency% | Duration | Memory Before | Memory After | Reduction% | Function
----------+-------------+----------+---------------+--------------+------------+---------
87815 | 878.15 % | 12.88 ms | 28461832 | 5090000 | 82.12 % | Dompdf\Css\Stylesheet::apply_styles
88140 | 881.40 % | 14.66 ms | 28556032 | 5090000 | 82.18 % | Dompdf\Css\Stylesheet::apply_styles
88140 | 881.40 % | 15.01 ms | 28556032 | 5090000 | 82.18 % | Dompdf\Css\Stylesheet::apply_styles
88140 | 881.40 % | 15.43 ms | 28556032 | 5090000 | 82.18 % | Dompdf\Css\Stylesheet::apply_styles