我的最终目标是为正在处理的计费项目创建发票作为PDF - 创建PDF是我已经完成的事情 - 我首先为每张发票创建一个HTML文件,然后在单独的流程中将HTML批量处理为PDF
然后我遇到的问题是,我试图进入HTML文件的数据非常大......它存储在MySQL中(我使用Symfony 1.4和Doctrine)。 php.ini目前设置为允许500M内存的PHP。我需要在同一个HTML / PDF文件中包含单个发票的所有invoiceLines。
我目前正在循环发票表(每张发票1行),然后从另一张表中获取发票的实际行(每张发票多行) - 我遇到的问题是内存使用量很大 - 任何人都可以建议这样做的另一种方式。
foreach ($invoices as $inv)
{
$outfile = '/ivoice' . $inv[0] . '.html';
$tempinvfile = fopen($outfile, 'w'); //open file and replace current it exists
echo '1 - Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;
$invoiceLines = Doctrine::getTable('InvoiceLine')
->createQuery()
->where('invoiceid = ?', $inv[0])
->setHydrationMode(Doctrine::HYDRATE_NONE)
->execute();
echo "Count = " . count($invoiceLines) . PHP_EOL;
echo '2 - Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;
$bodyhtml = '';
foreach ($invoiceLines as $invline)
{
// $bodyhtml .= '<tr>';
// $bodyhtml .= ' <td><b>' . $invline[2] . '</b></td>';
// $bodyhtml .= ' <td>£' . $invline[4] . '</td>';
// $bodyhtml .= ' <td>£' . $invline[5]. '</td>';
// $bodyhtml .= ' <td>£' . $invline[8] . '</td>';
// $bodyhtml .= ' <td>£' . $invline[9] . '</td>';
// $bodyhtml .= ' <td>£' . $invline[10] . '</td>';
// $bodyhtml .= ' <td>£' . $invline[12] . '</td>';
// $bodyhtml .= '</tr>';
}
echo '3 - Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;
// fwrite($tempinvfile, $bodyhtml);
// fclose($tempinvfile);
}
echo 'Used memory : ' . number_format(memory_get_usage() - $mem) . PHP_EOL;
echo "Done processing, time = " . (time() - $start) . PHP_EOL;
它产生的输出如下:
Starting Processing
1 - Used memory : 615,736
Count = 39
2 - Used memory : 1,033,264
3 - Used memory : 1,033,344
after end loop - Used memory : 1,033,344
1 - Used memory : 1,055,448
Count = 11
2 - Used memory : 1,118,200
3 - Used memory : 1,118,200
after end loop - Used memory : 1,118,200
1 - Used memory : 1,140,304
Count = 30340
2 - Used memory : 89,061,552
3 - Used memory : 88,977,472
after end loop - Used memory : 88,977,472
1 - Used memory : 88,999,576
Count = 156
2 - Used memory : 89,482,752
3 - Used memory : 89,482,752
after end loop - Used memory : 89,482,752
1 - Used memory : 89,505,368
Count = 3867
2 - Used memory : 100,737,248
3 - Used memory : 100,737,248
after end loop - Used memory : 100,737,248
Used memory : 100,737,248
Done processing, time = 0
所以我可以清楚地看到主内存的使用是从表中抓取invoiceLines的时候。但我不知道接近这个的最好方法.....我怎样才能在每个循环结束时回收内存?
我尝试过使用DoctrinePager并一次循环一个页面 - 工作但使用了更多的内存,以上方法。
建议非常受欢迎.....
编辑:
内存输出,所有文件操作已注释掉,并且在回显3之后添加了unset($invoiceLines)
:
Starting Processing
1 - Used memory : 615,712
Count = 39
2 - Used memory : 1,033,248
3 - Used memory : 1,033,328
after end loop - Used memory : 1,033,328
1 - Used memory : 1,055,432
Count = 11
2 - Used memory : 1,118,176
3 - Used memory : 1,118,176
after end loop - Used memory : 1,118,176
1 - Used memory : 1,140,280
Count = 30340
2 - Used memory : 89,061,760
3 - Used memory : 88,977,680
after end loop - Used memory : 88,977,680
1 - Used memory : 88,999,784
Count = 156
2 - Used memory : 89,482,968
3 - Used memory : 89,482,968
after end loop - Used memory : 89,482,968
1 - Used memory : 89,505,584
Count = 3867
2 - Used memory : 100,737,464
3 - Used memory : 100,737,464
after end loop - Used memory : 100,737,464
Used memory : 100,737,464
Done processing, time = 0
编辑2:@Crack的建议 - &gt;添加了profiler:false到databases.yml文件..这里是内存结果:
Starting Processing
1 - Used memory : 600,392
Count = 39
2 - Used memory : 1,006,768
3 - Used memory : 1,006,848
after end loop - Used memory : 896,352
1 - Used memory : 903,192
Count = 11
2 - Used memory : 954,624
3 - Used memory : 951,824
after end loop - Used memory : 922,576
1 - Used memory : 929,416
Count = 30340
2 - Used memory : 88,840,104
3 - Used memory : 88,751,672
after end loop - Used memory : 863,168
1 - Used memory : 870,008
Count = 156
2 - Used memory : 1,342,816
3 - Used memory : 1,340,016
after end loop - Used memory : 889,392
1 - Used memory : 896,232
Count = 3867
2 - Used memory : 12,117,080
3 - Used memory : 12,114,280
after end loop - Used memory : 915,616
Used memory : 915,616
Done processing, time = 0
答案 0 :(得分:0)
阅读1000行后使用fwrite()
,然后重置$ bodyhtml($bodyhtml = '';
)。这样你就不会在内存中存储一个大字符串。
修改强>
糟糕,Doctrine必须将所有先前读取的行存储在$invoiceLines
的某个缓存中...尝试查看php/symfony/doctrine memory leak?的解决方案。