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内存之外,也要考虑优化下程序哦。
php程序内存优化之数组操作优化的更多相关文章
- 05-02 Java 一维数组、内存分配、数组操作
数组的定义 动态初始化 /* 数组:存储同一种数据类型的多个元素的容器. 定义格式: A:数据类型[] 数组名; B:数据类型 数组名[]; 举例: A:int[] a; 定义一个int类型的数组a变 ...
- DOM操作优化
文档对象模型(DOM)是一个独立 于特定语言的应用程序接口.在浏览器中,DOM接口是以JavaScript语言实现的,通过JavaScript来操作浏览器页面中的元素,这使得 DOM成为了JavaSc ...
- 【SQL server初级】数据库性能优化三:程序操作优化
数据库优化包含以下三部分,数据库自身的优化,数据库表优化,程序操作优化.此文为第三部分 数据库性能优化三:程序操作优化 概述:程序访问优化也可以认为是访问SQL语句的优化,一个好的SQL语句是可以减少 ...
- 前端性能优化--为什么DOM操作慢? 浅谈DOM的操作以及性能优化问题-重绘重排 为什么要减少DOM操作 为什么要减少操作DOM
前端性能优化--为什么DOM操作慢? 作为一个前端,不能不考虑性能问题.对于大多数前端来说,性能优化的方法可能包括以下这些: 减少HTTP请求(合并css.js,雪碧图/base64图片) 压缩( ...
- 谈反应式编程在服务端中的应用,数据库操作优化,提速 Upsert
反应式编程在客户端编程当中的应用相当广泛,而当前在服务端中的应用相对被提及较少.本篇将介绍如何在服务端编程中应用响应时编程来改进数据库操作的性能. 开篇就是结论 接续上一篇<谈反应式编程在服务端 ...
- Oracle学习总结(8)—— 面向程序员的数据库访问性能优化法则
特别说明: 1. 本文只是面对数据库应用开发的程序员,不适合专业DBA,DBA在数据库性能优化方面需要了解更多的知识: 2. 本文许多示例及概念是基于Oracle数据库描述,对于其它关系型数据库也 ...
- Java集合类操作优化总结
清单 1.集合类之间关系 Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHas ...
- Java集合类操作优化经验总结
本文首先针对 Java 集合接口进行了一些介绍,并对这些接口的实现类进行详细描述,包括 LinkedList.ArrayList.Vector.Stack.Hashtable.HashMap.Weak ...
- 《Java程序性能优化》之设计优化
豆瓣读书:http://book.douban.com/subject/19969386/ 第一章 Java性能调优概述 1.性能的参考指标 执行时间: CPU时间: 内存分配: 磁盘吞吐量: 网络吞 ...
随机推荐
- 利用 OpenCC 工具进行文字的简繁转换
前言 近日在公司遇到一个需求,因为准备要推出海外版产品,所以需要将所有的简体文字转换为繁体文字.一开始是改了表面的文字,但是后面发现很多提示语也需要去改,所以找了一个工具去对所有 .m 文件进行批量文 ...
- Linux搭建图片服务器减轻传统服务器的压力(nginx+vsftpd)
传统项目中的图片管理 传统项目中,可以在web项目中添加一个文件夹,来存放上传的图片.例如在工程的根目录WebRoot下创建一个images文件夹.把图片存放在此文件夹中就可以直接使用在工程中引用. ...
- 列表list常用的方法
列表 name = ['Lisa', 'Mike', 'Jone', 'Lucy'] name.sort() # 排序,根据对应的ASCII码值,可以排各种类型的字符 name.append('Ms ...
- django之跨站请求伪造csrf
目录 跨站请求伪造 csrf 钓鱼网站 模拟实现 针对form表单 ajax请求 csrf相关的两个装饰器 跨站请求伪造 csrf 钓鱼网站 就类似于你搭建了一个跟银行一模一样的web页面 , 用户在 ...
- 构造函数new运算符进行了哪些操作
new 运算符 1,实例化一个对象 2,将构造函数prototype对象赋值给对象__proto__属性 3,将对象作为函数this传进去,函数有return 并且是对象的话,就直接返回return的 ...
- Python动态网页爬虫-----动态网页真实地址破解原理
参考链接:Python动态网页爬虫-----动态网页真实地址破解原理
- 【一起刷LeetCode】在未排序的数组中找到第 k 个最大的元素
题目描述 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 ...
- 【docker构建】基于docker搭建redis数据库缓存服务
搭建redis服务 首先拉取镜像==>运行镜像为容器 # 先搜索下redis镜像 [root@VM_0_10_centos wordpress]# docker search redis # 拉 ...
- go语言的错误处理
1.系统自己抛异常 //go语言抛异常 func test3_1() { l := [5] int {0,1,2,3,4} var index int = 6 fmt.Println(l) l[ind ...
- go语言之指针
package main import "fmt" //指针 //go语言的指针是非常容易学习的,比c中容易很多,他可以更简单的执行一些任务 //与变量类型,使用前需要定义 fun ...