如何修复 PHPExcel 耗尽的内存?

Posted

技术标签:

【中文标题】如何修复 PHPExcel 耗尽的内存?【英文标题】:How to fix memory getting exhausted with PHPExcel? 【发布时间】:2011-04-02 01:03:08 【问题描述】:

致命错误:允许的内存大小为 134217728 字节用尽(试图 分配 1078799 字节)在 D:\xampplite\htdocs\Scraper\phpExcel\Reader\Excel2007.php 第 269 行

我的 128M PHP 内存限制很快就会耗尽,即使我只是想用 PHPExcel 打开一个 ~350 KB 的小 Excel 文件。

虽然,我可以增加配置中的内存限制,但很高兴看看是否有任何替代方法可以解决此问题。

【问题讨论】:

找出 PHP Excel 中的什么占用了这么多内存,然后修复它..... @SoapBox:简而言之,PHPExcel - 它是一个真正的内存消耗者 :( 此外,它是一个复杂的库,因此找到(更不用说修复)一个错误相当重要。在在最坏的情况下,回避这个问题并找到一些替代库可能会更容易。 获得微软认证,只需要知道如何重启机器。这将释放泄漏软件使用的内存。 @SoapBox - 如果有人可以帮助我找到一种方法来降低 PHPExcel 的要求(而不会将其减慢到无法使用的程度),那么我很乐意实现它 【参考方案1】:

在使用 PHPExcel 时,文件大小不是衡量工作簿文件的好方法。行数和列数(即单元格)更为重要。

PHPExcel 代码本身的占用空间在 10 到 25MB 之间,具体取决于正在访问的组件。

目前,工作簿中的每个单元格平均占用 1k 内存(没有任何缓存)或 1.6k 在 64 位 PHP 上 - 我暂时假设 32 位 PHP - 所以(例如)一个工作表31 列(248,000 个单元)的 8000 行中的大小约为 242MB。使用单元缓存(例如 php://temp 或 DiskISAM),这可以减少到大约三分之一,因此 8000 行乘 31 列将需要大约 80MB。

有许多选项可帮助您减少内存使用量:

您是否在 PHPExcel 中使用单元缓存?

require_once './Classes/PHPExcel.php';

$cacheMethod = PHPExcel_CachedObjectStorageFactory:: cache_to_phpTemp;
$cacheSettings = array( ' memoryCacheSize ' => '8MB');
PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings);

$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objPHPExcel = $objReader->load("test.xlsx");

如果您只需要访问工作表中的数据,而不需要访问单元格格式,那么您可以禁用从工作簿中读取格式信息:

$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load("test.xlsx");

如果您只需要访问工作簿中的部分工作表,而不是所有工作表,则可以只加载这些工作表:

$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setLoadSheetsOnly( array("Worksheet1", "Worksheet2") );
$objPHPExcel = $objReader->load("test.xlsx");

如果您只想读取工作表中的某些单元格,可以添加过滤器:

class MyReadFilter implements PHPExcel_Reader_IReadFilter

    public function readCell($column, $row, $worksheetName = '') 
        // Read title row and rows 20 - 30
        if ($row == 1 || ($row >= 20 && $row <= 30)) 
            return true;
        

        return false;
    


$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadFilter( new MyReadFilter() );
$objPHPExcel = $objReader->load("test.xlsx");

所有这些技术都可以显着降低内存需求。

【讨论】:

5 年后:您的答案仍然是最新的吗? @robsch - Excel 文件在 5 年内没有改变它们的格式; PHP 内存限制在 5 年后仍然是 PHP 内存限制; PHPExcel 中仍然存在单元缓存和读取过滤器 作家怎么样,我用阅读器试试,但它不起作用。【参考方案2】:

PHPExcel 以内存泄漏而闻名。我建议您使用以下需要 PHPExcel 使用的内存的一小部分。:

1) 阅读:PHP-Excel-Reader

2) 写作:Pear Spreadsheet Excel Writer

【讨论】:

根据链接的网站“Spreadsheet_Excel_Writer 已过时,需要完全重写。如果您想帮助完成此任务,请与我们联系。否则我们不建议将此包用于新开发。 " 对于写作:PHP_XLSXWriter 内存使用率比 PHPExcel 低 95%。【参考方案3】:

仅仅因为数据文件只有 X 字节,并不意味着它使用 X 字节的内存。例如,$_SESSION 数组中只有 4K 的数据在加载时使用了 64K 的内存。它只取决于代码对这些数据做了什么。正确答案是增加ram的数量。

此外,如果这是一个 XLSX 文件,它们是 ZIP 格式的 XML 文档。文本文件的压缩比 1/2 小得多,因此您的 350K XLSX 文件很容易成为 1MB 的 Excel 文件。

【讨论】:

【参考方案4】:

Xdebug 是 php 的分析器/调试器,可以帮助您跟踪内存使用情况和函数调用,以找出问题所在。而且它易于安装,大多数 linux 发行版都在存储库中,“yum install xdebug”,“apt-get install xdebug”。

【讨论】:

【参考方案5】:

您也应该注意的一件事是空单元格。

我遇到了同样的问题,只有 800 行数据,脚本甚至无法读取。 修复后的超时和内存不足错误。

@Mark Ba​​ker 关于细胞的一些话让我开始思考。我注意到我有很多空单元格,并且只将带有数据的单元格复制到新工作簿中,它可以在一秒钟内运行。

希望这对某人有所帮助。

【讨论】:

【参考方案6】:

如果你想知道,可以使用xhprof。根据此链接,您可以使用它跟踪内存使用情况...

【讨论】:

【参考方案7】:
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load("test.xlsx");

这么多代码就够了

【讨论】:

【参考方案8】:

这篇文章讨论了如何关闭 PHPExcel 阅读器: How to close excel file in php-excel-reader 如果您同时打开多个 Excel 文件,但实际上并不同时需要它们,那么您可以尝试一个一个地打开和关闭(即取消设置)每个文件的阅读器。顺便说一句,为读者使用相同的变量名称就足够了“取消设置”操作。

【讨论】:

以上是关于如何修复 PHPExcel 耗尽的内存?的主要内容,如果未能解决你的问题,请参考以下文章

WordPress服务器不断耗尽内存并崩溃,我该如何确定和修复原因?

php excel的使用

tp5做的excel导入(用的PHPexcel类),有缺陷2007与2003只能二选一

python老司机必备-内存泄露分析优化

python老司机必备-内存泄露分析优化

如何解决PHP里大量数据循环时内存耗尽的问题