1

我的应用程序需要生成一个包含一堆图表的 pdf 文件。

情况:我使用 FPDF 生成 pdf,使用 JpGraph 生成图表。我的代码从数据库中获取图形数据并进行迭代,为每个包含所有 JpGraph 代码的图形调用一个函数,用于设置、设置图形样式并将其作为 png 文件缓存在服务器上的缓存文件夹中。FPDF 然后将这些图像放入 pdf 中,然后提供给浏览器。

问题:当图表数量超过一定数量时,我会遇到 PHP 内存不足错误。AFAICT 这不是 FPDF 问题:在尝试诊断问题时,我生成了更大的文档,其中包含更多(预生成的)图形和同等大小的图像。问题似乎是在图形渲染函数中用于渲染图形的内存在函数完成时没有被释放。这是基于这样一个事实,即如果我在函数中调用 memory_get_peak_usage,我会得到一堆递增的数字,每次调用函数时都会有一个,直到它停止时的限制为 64MB。

我的图形生成脚本如下所示:

function barChart($filename, $ydata, $xdata){

// Create the graph. These two calls are always required
$graph = new Graph(900,500);
$graph->SetScale('textlin');

//(bunch of styling stuff)

// Create the bar plot
$bplot=new BarPlot($ydata);

// Add the plot to the graph
$graph->Add($bplot);

//(more styling stuff)


// Display the graph
$graph->Stroke($filename);

$graph = null;
$bplot = null;

unset($graph);
unset($bplot);

echo "<br><br>".(memory_get_peak_usage(true)/1048576)."<br><br>";
}

如您所见,我尝试取消设置和取消图形和 bplot 对象,尽管我的理解是这不是必需的。当函数完成时,不应该释放 Graph 和 Bplot 实例使用的所有内存吗?或者这可能是 JpGraph 内存泄漏?(我到处搜索,找不到其他人抱怨这个)。这是我的第一个远程资源密集型 PHP 项目,所以我可能会遗漏一些明显的东西。

4

3 回答 3

8

我遇到了同样的问题,并在一个小时左右后找到了解决方案。

问题是 jpgraph每次创建 Graph 时都会加载一组默认的字体文件。我找不到卸载字体的方法,所以我做了一点改动,让它只加载一次字体。

要修复您的安装,请编辑“gd_image.inc.php”,如下所示:

在文件开头附近的某处添加以下内容(就在 CLASS 图像之前):

// load fonts only once, and define a constant for them
define("GD_FF_FONT0", imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT0.gdf"));
define("GD_FF_FONT1", imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1.gdf"));
define("GD_FF_FONT2", imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2.gdf"));
define("GD_FF_FONT1_BOLD", imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1-Bold.gdf"));
define("GD_FF_FONT2_BOLD", imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2-Bold.gdf"));

然后在 Image 类构造函数的末尾(第 91-95 行),替换为:

$this->ff_font0 =  imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT0.gdf");
$this->ff_font1 =  imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1.gdf");
$this->ff_font2 =  imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2.gdf");
$this->ff_font1_bold =  imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1-Bold.gdf");
$this->ff_font2_bold =  imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2-Bold.gdf");

有了这个:

$this->ff_font0 =  GD_FF_FONT0;
$this->ff_font1 =  GD_FF_FONT1;
$this->ff_font2 =  GD_FF_FONT2;
$this->ff_font1_bold =  GD_FF_FONT1_BOLD;
$this->ff_font2_bold =  GD_FF_FONT2_BOLD;

我没有使用多个版本的 php 或 jpgraph 对此进行测试,但它应该可以正常工作。ymmv。

于 2012-12-13T19:48:45.360 回答
3

您可以尝试使用 PHP >= 5.3 垃圾收集

gc_enable()+gc_collect_cycles()

http://php.net/manual/en/features.gc.php

于 2012-11-06T14:43:53.767 回答
0

@bobD 的回答是正确的,并帮助解决了我同样的问题。

然而,对于那些仍在寻找这个非常古老问题的答案的人来说,还有另一个潜在的内存泄漏源。

如果您使用相同的背景图像创建多个图表,则每次加载背景图像都会导致每次创建图表时内存增加。

与 bobD 对字体加载问题的回答类似,这可以通过使背景图像成为全局变量而不是每次都加载来解决。

编辑:看起来在使用 MGraph() 时也存在非常小的内存泄漏。

特别是函数 Add()。也许它还会在每个递归调用中加载一个字体库或类似的东西。

于 2019-06-12T04:35:18.470 回答