谁动了我的内存之PHP内存溢出

今天上午刚到公司,就有同事在公司群里反映某个计划任务出现问题了。我就怀着刨根问底的心,去查看了log。发现挺有意思的一个问题,PHP内存溢出导致脚本执行失败。那就一起来看个究竟吧!

  1. 首先查看了计划任务的Log
    log_error.png

从报错信息字面意思可以看出,允许的134217728 bytes的内存已经用尽,还要试图分配12961640 bytes内存。
给你(当前脚本)分配的内存你已经用完了,你还想问系统要内存。系统这时想对你说:

地主家也没有余粮啊(借用葛优大爷的一句话)

geyou.png

    1. 模拟一下"案发现场"

    • 新建一个mem_exhausted.php文件 copy过来一个2.4M的log文件做测试用
      log_size.png

    • 写个简单的脚本重现"案发现场" 故意分配1M的内存 来读取2.4M的log
      test_mem_1.png

    • 执行脚本,"案发现场"重现
      test_run_res.png

    1. 分析"事故"原因
      脚本一次性读取了大量的数据(可能是读的文件,可能是读取的数据库)

    如下图: 往杯子(分配给当前脚本的内存)里面倒数水(log文件的数据),杯子容量(内存)不够用
    water_overflow.jpg

    1. 解决方案

      1. 既然杯子小 就换个大杯子(增大给脚本分配的内存)治标不治本: ini_set('memory_limit','100M');
        new_1.png

      2. 把水分批次倒入杯子中(循环,分段读取数据,读数据库的话可以用limit)

    code_1.png

    看看结果

    run_res_new.png

    分段读取也是可以解决问题滴

    1. 其他优化方案

      • 应当尽可能减少静态变量的使用,在需要数据重用时,可以考虑使用引用(&)。

      • 数据库操作完成后,要马上关闭连接;

      • 一个对象使用完,要及时调用析构函数(__destruct())

      • 用过的变量及时销毁(unset())掉

      • 可以使用memory_get_usage()函数,获取当前占用内存 根据当前使用的内存来调整程序

      • unset()函数只能在变量值占用内存空间超过256字节时才会释放内存空间。(PHP内核的gc垃圾回收机制决定)

      • 有当指向该变量的所有变量(如引用变量)都被销毁后,才会释放内存
        (PHP变量底层实现是一个_zval_struct结构体,refcount_gc表示引用计数 is_ref__gc表示是否为引用)

    -------------------------我是分割线-------------------------

    硬广时间(对Nginx感兴趣的童鞋可以看下)

    Nginx系列课程索引

    1. 引子: WebServer与PHP通信姿势
      熟悉了解Nginx与PHP是怎么进行通信的

    2. 起手式: PHP程序猿应该知道的Nginx (上)
      如何更好的使用Nginx和Nginx配置

    3. 进阶式: PHP程序猿应该知道的Nginx (中)
      深入理解Nginx内核和Nginx运行原理,剖析Nginx高性能的秘密

    4. 实战篇: PHP程序猿应该知道的Nginx (下)
      百闻不如一run 一起来开发一个Nginx的拓展


    代码与远方
    生活不止眼前的苟且,还有代码和远方。

    一个程序猿,喜欢学习技术,喜欢交流技术

    3.4k 声望
    1.2k 粉丝
    0 条评论
    推荐阅读
    Hackintosh (黑苹果) 折腾
    EFI 引导文件可以去 git clone https://github.com/wujunze/ASRock-Z370-Pro4-9900K-Hackintosh

    CodeCloud1阅读 2.1k

    如何定位内存溢出导致页面崩溃问题
    在实际项目开发中,我们常常会遇到类似如下页面崩溃的问题,导致浏览器页面崩溃的原因一般都是JS Heap堆内存溢出,但此类问题一般控制台都不会报错,所以其定位问题的经验和手段很关键,下文是我在实际项目中遇到...

    记得要微笑10阅读 3.1k

    PHP转Go实践:xjson解析神器「开源工具集」
    我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

    王中阳Go11阅读 2.7k评论 4

    封面图
    Git操作不规范,战友提刀来相见!
    年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

    王中阳Go6阅读 2.9k评论 4

    封面图
    图片防盗链破解 解决图片防盗链问题 反向代理
    当客户端(浏览器)向服务器请求内容的时候,会提交一个header,这个header中包含了如:浏览器信息、cookie等内容,那么有一个叫referer的东东,也包含在这里面。

    TANKING7阅读 11.7k评论 5

    Hyperf 3.0 发布,PHP 新时代
    在过去的一年半时间里,Hyperf 2.2 共发布了 35 个小版本,使 Hyperf 达到了一个前所未有的高度,这里也获得了一些不错的数据反馈。

    huangzhhui4阅读 1.5k评论 1

    封面图
    微信公众号开发:自动回复文本/图片/图文消息/关键词回复/上传素材/自定义菜单
    对接流程1、申请微信公众号测试账号URL:[链接]2、登录,配置开发者服务器URL和Token开发者服务器配置代码:config.php {代码...} URL是config.php在你服务器的URLToken是上面代码自己设置的Token搞定之后,就能完...

    TANKING2阅读 10.5k

    一个程序猿,喜欢学习技术,喜欢交流技术

    3.4k 声望
    1.2k 粉丝
    宣传栏