zoukankan      html  css  js  c++  java
  • php程序内存优化之数组操作优化

    一、前言
    这篇文章其实是上篇文章的内存优化部分。博主的php程序在执行的时候,报错:

    Out of memory (allocated 364904448) (tried to allocate 262144 bytes)

          也就是传统的内存不足报错,问题是我本地设置的内存已经是1280M了,简直不能忍。因此这里一步步的看一篇代码,记录一下需要优化的地方,主要是针对数组的

    二、优化前准备

    1、首先是查看php的当前内存设置

    windows: 打开php.ini,搜索:memory_limit ,一般设置为128M够用
    linux: 执行“php -i | grep Loaded Configuration File”来找到对应的配置文件。

    注: 这个命令是搜索php程序的配置文件所在位置,打开phpinfo,可以看到有个Loaded Configuration File 选项,对应
    的就是php.ini文件的位置

    2、一个php数组能占用多大内存

    参考:https://blog.csdn.net/hguisu/article/details/7376705

    通过大佬的分析,我们可以知道:

    (1)php对于数组的利用效率很低,一个在C语言里面100M 内存的数组,在PHP里面就要1G;
    (2)php空数组都要14(zval) + 39(HashTable) + 33(arBuckets) = 86 个字节
    (3)php查看内存方法:memory_get_usage() ,具体用法: echo memory_get_usage(); 即可,博主通过该方法,确认内存瓶颈出在了数组部分

    三、优化过程
    1、代码冗余

    $arr = [];
    foreach($response['hits']['hits'] as $v)
    {
    $arr[] = $v['_source'];
    }
    unset($v);
    //加上原来没有的一些字段,筛选掉没有pixel的数据
    foreach($arr as $key=>$v){
    if(!array_key_exists('pixel.uuid',$v)){
    unset($arr[$key]);
    }
    }

    优化点评: 这里的$arr是完全不必要的,既然下面还是要筛选,那么直接循环下面的那个$response['hits']['hits']即可,如果$arr是很大的数组,那么在赋值之后,又要开辟一块内存给它。所以要尽量避免这种情况的发生。

    2、数组赋值给另一个空数组

    if(count($this->arrEsIndex) > 0){
    unset($this->arrEsIndex);
    $this->arrEsIndex = $arr;
    }else{
    $this->arrEsIndex = $arr;
    }

    优化点评: 像这种数组赋值操作尽量少做。因为把 $arr赋值给$this->arrEsindex之后,如果$this->arrEsIndex的值改变了,那么使用的内存相当于翻倍的效果。其次是赋值之后,这个$arr其实已经没用了,但是由于咱们没有进行unset,所以就造成这个$arr还在占用内存的情况。建议是unset($arr),也就是unset掉咱们不用的那些数组。

          正常的赋值是不会发生内存改变的,但是当赋值的新数组发生改动的时候,php就会新开辟内存给新的数组,这里会造成无谓的内存消耗。最好是不要直接这样赋值,如果非赋值不可的话,记得加上‘&’符号,通过传引用直接传递地址给新数组,这样当新数组发生变化的时候,更改的还是原来的那块内存。

    3、把数组传参给函数

    $this->getScrollData($repos);

    优化点评: 这里的$repos是一个数组。正常来说,传值传数组也是可以的,但是如果这个数组里面的元素是万级别的,那么
    这个操作也是非常耗内存的。在php程序中,只要传参,参数都会拷贝一份,所以值越大,耗的内存越大。针对这种情况,
    建议是在类里面定义全局变量,然后函数体里面通过:$this->repos来操作这个数组。也可以考虑使用传引用的方式,因为使用&的话,传递过去的事一个内存地址,位数并不大。

    4、把判断条件写在循环外面,避免每次都要循环的情况

    foreach($this->arrEsIndex as $k=>&$v) {
    if (!empty($this->search_abtest_key) && $this->search_abtest_key != "is_50mclient") {
    $v[$this->search_abtest_key] = 0;
    }
    }

    优化点评: 这个操作也有问题,如果if条件满足的话还好。如果If条件不满足的话,在业务层面根本就不需要进行这部分操作。但是由于咱们的forteach循环在最外面,所以照样会循环一下数组。问题这是个很大的数组,消耗的内存也很可观。

    5、unset掉比较大的变量

          针对一些比较大的变量(最好大于256字节),如果只是临时使用的话,使用完之后记得unset()掉。如果对变量进行'&'传引用的话,会增加该内存的引用计数,直接unset()变量并不会立马释放变量,因为unset只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数-1,如果把引用赋值的那个变量也unset()掉才会立马释放内存。

    6、单个大数组消耗太多内存的解决方案

          参考:http://www.phpzy.com/php/16958.html

          通过存入字符串的方式优化,使用数组的时候就再把字符串转化为数组

    7、循环操作DB

          这个问题是老生常谈了,博主代码里没有出现这个情况,不过大家还是注意下比较好。循环不断操作DB,非常影响程序性能。

    四、总结
          以上的优化部分也是博主一步步看着代码慢慢优化的,相对而言都是一些比较浅层面的优化。不过这些问题也告诉我们,写完代码记得要再看一遍,如果可以的话,在开始编写代码的时候就要注意性能问题。最差劲也要实现业务之后,重新看一遍代码,优化代码结构,释放掉不必要的变量,改掉太消耗内存的操作。

          博主这里优化之后,原来的代码1280M的内存都不够用,现在128M的内存妥妥的。程序执行下来,总共占用内存10M左右,还是比较合适的。如果大家也出现内存不足的情况,那么除了增大本身的php内存之外,也要考虑优化下程序哦。

    有需要交流的小伙伴可以点击这里加本人QQ:luke

  • 相关阅读:
    i春秋——春秋争霸write up
    2017-2018-2 《网络对抗技术》20155322 Exp6 信息搜集与漏洞扫描
    2017-2018-2 《网络对抗技术》 20155322 Exp 5 MSF基础应用
    OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现
    2017-2018-2 《网络对抗技术》 20155322 Exp4 恶意代码分析
    MacOS下netstat和lsof使用的若干问题
    OpenCV学习系列(零) Mac下OpenCV + xcode环境搭建
    2017-2018-2 《网络对抗技术》 20155322 Exp3 免杀原理与实践
    2017-2018-2 《网络对抗技术》 20155322 第五周 Exp2 后门原理与实践
    信息安全铁人三项赛--资质赛writeup
  • 原文地址:https://www.cnblogs.com/starluke/p/11782396.html
Copyright © 2011-2022 走看看