【问题标题】:PHP Fatal error allowed memory size exhaustedPHP致命错误允许内存大小耗尽
【发布时间】:2017-12-13 22:52:35
【问题描述】:

我正在编写一个 codeigniter 应用程序,在执行查询时遇到以下致命错误。

致命错误:允许的内存大小为 134217728 字节已用尽(已尝试 在 /var/www/html/cryd/_zcore/core/Loader.php 中分配 262144 字节) 在第 262 行

我可以增加允许的内存大小,但似乎问题可能更严重,如果是内存泄漏,我只会给 php 更多的内存来玩。查询甚至没有那么密集,它只返回一行数据。

这是我的控制器

    <?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Invest_webhook extends CI_Controller {


    private $web_msg = null;
    private $proceed = 1;
    private $data = null;
    private $receive = null;
    private $complete = 0;
    private $member = null;
    private function loadPage($page,$data=null){
        $data = array_merge($data,$this->lang->language);
        $this->parser->parse('dashboard/header',$data);
        $this->parser->parse('dashboard/'.$page);
        $this->parser->parse('dashboard/footer');
    }

    public function webhook(){
        echo memory_get_peak_usage()."<br/>";
        //$update = file_get_contents("php://input");
        //$update = json_decode($update,true);

        $update = array(
            'notification_id' => '57233292b6a3d133e9c83822',
            'delivery_attempt' => 1,
            'type' => 'address',
            'data' => Array(
                'network' => "BTCTEST",
                'address' => '2N1jfZt8Uc721FAWNjdVpQZjfTxeG271RKy',
                'balance_change' => 1.00000000,
                'amount_sent' => 0.00000000,
                'amount_received' => 1.00000000,
                'txid' => '',
                'confirmations' => 4,
                'is_green' => false
            ),
            'created_at' => 1497176944
        );

        $data = $this->get_investment_data($update['data']['address']);
        if(!$data){
            die('This address does not exist');
        }

        $this->data = $data[0];
        $this->member = $this->get_member_data($this->data['tid']);

        //Start the process to verify transaction and credit investment
        $this->verify_investment();
        $this->update_investment();

        //$parameter = $this->web_msg;
        //include APPPATH."libraries/telegrambotv2.php";
        //$bot = new Telegram('331263599:AAEpHNAdyN1X5TenBk_QkJdt7xfwzDI6YeQ','bot');

        echo $this->web_msg."<br/>";        
    }

    private function verify_investment(){
        include APPPATH."/libraries/BlockIo.php";
        $this->load->config('block');
        $block = new BlockIo($this->config->item('api_token'),$this->config->item('api_secret'));
        $address = ($this->data['address']);
        $receive = $block->get_address_balance(array('addresses' => $address));

        $receive = $receive->data->available_balance;


        $expect = $this->data['inv'];

        settype($receive,'float');
        settype($expect,'float');
        echo '<br/>'.$receive."<br/>".$expect."<br/>";
        if($receive == $expect){

            $this->receive = $receive;
            return true;
        }
        $this->proceed = 0;
        $this->web_msg = 'inv_mismatch';
        return false;
    }

    private function get_member_data($tid){
        $this->load->model('invest_model','invest');
        return $this->get_member_data($tid);
    }

    private function update_investment(){
        if(!$this->proceed){
            return;
        }
        $this->load->model('invest_model','invest');

        $einv = $this->member['inv'];


        settype($einv,'float');

        $new_inv = $einv + $this->receive;
        $this->member['inv'] = $new_inv;
        $this->member['last_inv'] = 'NOW()';
        $this->data['confirmed'] = 1;

        if($this->invest->update_investment($this->data,$this->member)){
            $this->web_msg = 'inv_complete';
            $this->complete = 1;
            return true;
        } else {
            $this->proceed = 0;
            $this->web_msg = 'inv_unx_err';
            return false;
        }
    }

    private function get_investment_data($address){
        $this->load->model('invest_model','invest');
        return $this->invest->investment_data($address);
    }

    private function log($text){
        $file = fopen(APPPATH."/logs/investments/log.log",'a');
        fwrite($file,$text);
        fwrite($file,"\n");
        fclose($file);
    }
}

这是我的模型

    <?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Invest_model extends CI_Model {
    public function __construct(){
        parent::__construct();
    }

    public function investment_data($address){
        $this->db->where('address',$address);
        $this->db->where('confirmed',0);
        $f = $this->db->get('investments');
        return $f->result_array();
    }

    public function current_investment($tid){
        $this->db->select('inv');
        $this->db->where('tid',$tid);
        $f = $this->db->get('users');
        $f = $f->row_array();
        return $f;
    }

    public function get_member_data($tid){
        echo "<hr/>";
        echo memory_get_peak_usage()."<br/>";
        $this->db->where('tid',$tid);
        echo memory_get_peak_usage()."<br/>";
        $f = $this->db->get('users');
        echo memory_get_peak_usage()."<br/>";
        return $f->row_array();
    }

    public function update_investment($inv,$member){
        $this->db->trans_begin();
        $this->db->set($inv);
        $this->db->where('address',$inv['address']);
        $this->db->update('investments');
        $this->db->set($member);
        $this->db->where('tid',$member['tid']);
        $this->db->update('users');
        if($this->db->trans_status() === FALSE){
            $this->db->trans_rollback();
            return false;
        } else {
            $this->db->trans_commit();
            return true;
        }
    }

}

我不知道我可以在哪里进一步优化它,它非常简单直接,如果它在我的逻辑方法中存在问题,希望比我更好的头脑能够发现并进一步指导我。

提前致谢。

【问题讨论】:

  • 我没有看到任何可能是原因的 for 或 while 循环。递归调用也可能导致这种情况。您正在使用的 DB 层是什么,例如$this-&gt;db-&gt;get
  • @Adder 你的意思是我正在使用的驱动程序吗?它的mysqli。
  • 我不知道 mysqli 允许做$this-&gt;db-&gt;where,我猜这是来自一些本土数据库层。
  • 一件很奇怪的事情 - 你的目录结构/var/www/html/cryd/_zcore/core/Loader.php 看起来不对,Loader.php 应该在 [your_directory]system/core/ - 你的 CI 版本是多少?
  • @sintakonte 已将 codeigniter 安装配置为使用单独的应用程序文件夹和单独的核心文件夹。所有核心系统都在 _zcore 里面,而所有应用程序都在 _botadmin 里面

标签: php codeigniter memory-management memory-leaks max


【解决方案1】:

您的代码看起来不错。检查某个函数是否被重复调用。

你可以使用

ini_set('memory_limit', '-1');

作为临时解决方案。或者只是增加memory_limit

检查您的php.ini 文件。如果是下面的形式,

memory_limit=8G

MB

的形式更改它
memory_limit=8192M

你也可以在你的代码中这样做

ini_set('memory_limit', '8192M'); 

【讨论】:

    【解决方案2】:

    将此行放在您的 codeigniter 的 index.php 上。所以整个项目都会受到影响。

    ini_set('memory_limit', '-1');
    

    注意:这只是一个快速修复。 php 本身没有解决这个错误。

    【讨论】:

    • 好吧,这会起作用,但我只是想知道它是否在我的代码中。没有到数据库或任何东西的递归连接。
    • 你的意思是,你不知道是什么导致了这个问题?
    • 是的,我不知道是什么原因造成的。最多调用 3 次数据库以从 2-3 个表中检索信息,然后更新一次查询。这些都不是递归发生的。我必须添加标志来检查这一点
    • 在每次调用前后检查内存使用情况。
    • 控制器中的私有方法一遍又一遍地调用自己,直到分配的内存耗尽。
    【解决方案3】:

    如果其他人有这个问题:

    确保您在 php.ini 中的内存大小在数字后有一个 M。

    我有 512 在那里....当我把它改成 512M .....没有问题了。

    z

    【讨论】:

      【解决方案4】:

      如果您想知道内存的去向,您应该查看 PHP 内存分析:PHP memory profiling

      我个人会将 PHP max_memory 增加到 256MB,看看是否足够;)

      【讨论】:

        【解决方案5】:

        出现问题是因为私有方法不断调用自身,直到分配的内存耗尽并且脚本停止执行

        private function get_member_data($tid){
            return $this->get_member_data($tid);
        }
        

        这是一个愚蠢的人为错误,上面的方法应该重写如下

        private function get_member_data($tid){
        //Call to model method
            return $this->invest->get_member_data($tid);
        }
        

        对不起,谢谢大家。

        【讨论】:

          猜你喜欢
          • 2011-07-12
          • 2015-05-30
          • 1970-01-01
          • 2020-08-21
          • 2015-11-25
          • 1970-01-01
          • 2014-02-15
          • 1970-01-01
          • 2013-10-21
          相关资源
          最近更新 更多