最近我们公司做了一个对账平台,我负责做报表这一块。我发现用 PHPExcel 导出5000条以上的数据就出现了这个问题(php.ini 的默认的内存限制是 128M)
|
|
最先想到的是修改 php.ini 的内存限制,但这个方法制标不制本,只能寻找别的解决方法。
下面简单阐述一下我的解决过程
|
|
|
|
以下测试数据都是基于导出 5000 条数据产生的
| 过程 | 查询数据前 | 查询数据后 | 遍历数据 |
|---|---|---|---|
| 优化前 | 6M | 26M | 70M |
通过 php 函数 memory_get_usage 可以获取到如上数据。可以发现,内存占用大的情况出现在查询后和遍历 Excel 数据的时候。
PHPExcel 大数据量情况下内存溢出解决
PHPExcel 可以通过缓存来解决这种情况,大家可以参考这篇 文章 来解决遍历数据那一步
|
|
| 过程 | 查询数据前 | 查询数据后 | 遍历数据 |
|---|---|---|---|
| 优化后 | 6M | 26M | 51M |
注销遍历完的变量
在上面的代码中,$data 是存了 5000 条数据的变量,占用了较大的内存。我们遍历完数据后这个变量也就没用了,所以我们可以用 unset() 来的注销这个变量。
但是重点在下文的生成器,就算不用 unset() 也没关系了。
| 过程 | 查询数据前 | 查询数据后 | 遍历数据 | 注销变量 |
|---|---|---|---|---|
| 优化后 | 6M | 26M | 51M | 35M |
应用 PHP 的生成器
官方注释:生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
我最近在学习 python,看到了生成器这部分,想起了 PHP 也有生成器。我们不可能把成千上万条数据存到变量中,这样内存一下子就达到上限了。但我们可以利用生成器,代码如下:
|
|
| 过程 | 查询数据前 | 查询数据后 | 遍历数据 |
|---|---|---|---|
| 最初 | 6M | 26M | 70M |
| 最终 | 6M | 6M | 31M |
经过测试,查询数据前后的内存占用基本不变。经过上面几步的优化,遍历数据那一步现在的内存占用也只有 31M 了。就算是 php.ini 默认的 128M 的内存也足够用了。关于生成器的详细介绍,大家可以去看 PHP 官方手册。
我发现网上在解决这个问题没有用上生成器,所以便有了这篇文章。解决了这类问题还是满有成就感的,嘿嘿!