【问题标题】:PHPExcel Writer object uses huge memory and time outs eventuallyPHPExcel Writer 对象最终使用巨大的内存和超时
【发布时间】:2015-04-15 09:33:22
【问题描述】:

我正在使用以下方法创建一个 excel 表:

  1. Codeigniter 2.2.1
  2. PHP 5.4.25
  3. Apache 2.4.7
  4. XAMPP 1.8.2
  5. PHPExcel 1.8.0

我正在从数据库中获取 35000 行(大部分为空),其中包含 79 列,并写入 Excel 文件 (Excel5)。

它适用于 30000 行,峰值内存使用量为 1.44GB,文件大小为 24MB。但是当我去 35000 它超时说,

致命错误:E:\XAMPP\htdocs\ProjectName\application\libraries\PHPExcel\Writer\Excel5\BIFFwriter.php 第 144 行内存不足(已分配 1780219904)(试图分配 17301483 字节)

当我创建 PHPExcel 对象时,它最终会使用大量内存并超时。我在 php.ini 文件中设置了 "memory_limit= -1" 和 "ma​​x_execution_time= 1000" 并在 PHPExcel 中尝试了不同的缓存存储方法。

我在控制器中的算法是这样的

public function write_controller() {    
    error_reporting(E_ALL);
    ini_set("display_errors", 1);
    ini_set('memory_limit', '-1'); //-1 for unlimited memory
    $dir = "assets/output/";

    //FIRST CHECK IF PREVIOUS FILE EXISTS OR NOT
    $this->clear_directory($dir);

    // Loading PHPExcel library
    $this->load->library('PHPExcel');
    $this->load->library('PHPExcel/IOFactory');

    $cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp;
    $cacheSettings = array('memoryCacheSize' => '5000MB', 'cacheTime' => '1000'); 

    PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings);

    //First Create the xls file and then insert rest of the data
    $objPHPExcel = new PHPExcel();
    $objPHPExcel->getProperties()->setTitle("export")->setDescription("none");

    //activate sheet number 1
    $objPHPExcel->setActiveSheetIndex(0);

    //Setting font styles
    $objPHPExcel->getActiveSheet()->getDefaultStyle()->getFont()->setName('Arial')->setSize(8)->setBold(false);

    //Setting number format as TEXT
    $objPHPExcel->getActiveSheet()->getDefaultStyle()->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_TEXT);

    //Freezing first top row
    $objPHPExcel->getActiveSheet()->freezePane('A2');


    $objWorksheet = $objPHPExcel->getActiveSheet();

    $row1 = 1;

    $objWorksheet->setCellValueByColumnAndRow(0, $row1, "Site name");
    $objWorksheet->setCellValueByColumnAndRow(1, $row1, "Vendor_1");
    $objWorksheet->setCellValueByColumnAndRow(2, $row1, "Status");
    $objWorksheet->setCellValueByColumnAndRow(3, $row1, "Easting");
    $objWorksheet->setCellValueByColumnAndRow(4, $row1, "Northing");
    $objWorksheet->setCellValueByColumnAndRow(5, $row1, "Sector_1");
    .
    .
    .
    //Rest of the 74 columns

    $style = array(
        'alignment' => array(
            'horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_CENTER, 
            'vertical' => PHPExcel_Style_Alignment::VERTICAL_CENTER)
    );

    $objWorksheet->getDefaultStyle()->applyFromArray($style);

    $objWriter = IOFactory::createWriter($objPHPExcel, 'Excel5');

    $saved_location ='assets/output/Piano11.xls'; 
    $objWriter->save($saved_location); 

    //Now reading the saved xls file
    $objReader = new PHPExcel_Reader_Excel5();

    $newPHPExcel = $objReader->load($saved_location); 

    $newWorksheet = $newPHPExcel->getActiveSheet();

    //Now insert rest of the data from Piano table which will come from database
    $table_name = 'piano_test';

    $query = $this->db->get('tbl_piano');

    if (!$query) {
        return false;
    }

    // Fetching the data from table
    $fields = $query->list_fields();

    $row = 2;
    foreach ($query->result() as $data) {
        set_time_limit(0);
        $col = 0;
        foreach ($fields as $field) {
            $newWorksheet->setCellValueByColumnAndRow($col, $row, $data->$field); //<- This skips leading 0s
            $col++;
        }
        $row++;
    }

    $newobjWriter = IOFactory::createWriter($newPHPExcel, 'Excel5');
    $newobjWriter->save('assets/output/Piano11.xls');

    echo 'Memory peak usage: <b>'.$this->convert(memory_get_peak_usage(true)).'</b><br/>';
    gc_collect_cycles();//garbage collector
    echo 'inserted.';
}

任何解决方案如何最大限度地减少内存使用和执行时间?或任何其他替代解决方案?或者我应该改变我的算法吗?

【问题讨论】:

  • 清除内存,计算所需的数量与清除你可以清除的数量,然后使用 memory_limt davidwalsh.name/increase-php-memory-limit-ini_set... 这些都是我所需要的,我处理 80+gb 的地理数据库 .. 你会有内存泄漏什么的。有时最好对它进行批处理。检查您的 PHP 版本是否存在已知的内存泄漏,因为这种情况经常发生。试试airpair.com/php/fatal-error-allowed-memory-size 否则你可能不走运.. 它在某种程度上一直是个问题
  • 当您在此脚本中创建多个 Writer 时,您可能希望在调用 Writer 的 save() 方法后取消设置
  • 您可以看到我已将内存限制设置为-1,这是所有可能的内存分配。

标签: php codeigniter-2 phpexcel


【解决方案1】:

您正在使用 phptemp 进行缓存,但需要设置

$cacheSettings = array('memoryCacheSize' => '5000MB', 'cacheTime' => '1000'); 

这意味着 PHPExcel 在开始使用 phptemp 进行缓存之前将使用 5000MB (5GB) 的 PHP 内存.....如果您有 php.ini 最大内存设置允许 PHP 使用,我会感到惊讶这么多内存

您应该为memoryCacheSize 使用低得多的值,也许是512MB,这意味着PHPExcel 在切换到使用php://temp 之前将只使用512MB 的PHP 内存来缓存单元格数据

【讨论】:

  • 我已经更改并对其进行了测试,但由于您是 PHPExcel 版主,我问您,编写 excel 表的可能(或最佳)缓存方法是什么?另一方面,如果执行时间和内存对我来说不是问题,我该如何解决这个问题?
  • 在内存方面最有效的缓存方法是 SQLite 或 SQLite3,但它比其他一些方法慢.... 确实没有“最好”这样的东西,因为它取决于个人情况
  • 如果您正在处理大量数据,将任务作为后台进程运行通常也是一个好主意,可能是从命令行而不是作为 Web 请求,因为您不是t 时间限制以同样的方式
  • 是的,我已经在 Windows 7 的任务计划程序中运行了这个脚本,但是没有运气!但最后我设法将表格导出为 CSV,然后使用 PHPExcel 转换(经过修改)为 Excel5。
猜你喜欢
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 2011-04-04
  • 1970-01-01
相关资源
最近更新 更多