Zend_Mail:如何修复PHP致命错误:允许的内存大小耗尽?

时间:2009-12-31 19:37:37

标签: php zend-framework zend-mail

我有一个cron作业,它将电子邮件发送到订阅者列表,一个foreach循环中一次一个,带有PDF附件。我从cron脚本中得到了这条消息:

Fatal error: Allowed memory size of 94371840 bytes exhausted (tried to allocate 78643193 bytes)

我需要做些什么来防止此错误?

另外,我很确定它没有完成发送给所有订阅者,所以我应该如何跟踪这一点,以便它知道如果没有发送给每个人又在哪里重新开始?

更新程序:这是一个代码示例:(我顺便使用Zend Framework)

public function send(Default_Model_MyEmail $myEmail)
{
    if (null != ($id = $myEmail->attachmentId)) {
        $file = new Default_Model_File();
        $file->find($id);
        $filepath = APPLICATION_UPLOADS_DIR . '/' . $file->getActualFilename();

        $attachment = new Zend_Mime_Part(file_get_contents($filepath));
        $attachment->type = $file->getMimeType();
        $attachment->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
        $attachment->encoding = Zend_Mime::ENCODING_BASE64;
        $attachment->filename = $file->getDisplayFilename();    
    }
    $transport = new Zend_Mail_Transport_Smtp('localhost');

    $mail = new Zend_Mail('utf-8');
    $mail->setFrom('from@address', 'From Name');
    $mail->setReplyTo('replyto@address');
    $mail->setSubject($myEmail->subject);
    if (isset($attachment)) {
        $mail->addAttachment($attachment);
    }

    $subscribers = $this->getSubscribers();
    foreach ($subscribers as $subscriber) {
        $mail->addTo($subscriber->email);
        $bodyText = $myEmail->body
            . "\r\n\r\nIf for any reason you would like to be removed from this mailing list, "
            . "please visit \r\nhttp://myapp.com/myemail/unsubscribe/email/"
            . $subscriber->email;
        $mail->setBodyText($bodyText);
        $mail->send($transport);
        $mail->clearRecipients();
    }
}

更新:我正在重复使用$transport变量。我认为这是发送给多个订阅者的正确方式,但也许这是原因?你觉得怎么样?

更新:我添加了一堆打印内存使用情况语句的日志语句,但我现在还不知道该怎么做。每封电子邮件的内存使用量都会增加如果订户列表为200,则会达到160,然后内存不足。我该怎么办?

4 个答案:

答案 0 :(得分:2)

看起来您的代码正在尝试根据错误消息分配78 MB的块。

检查您的代码是否有可能尝试并一次分配大量内存的任何内容。这可能不是由于未能释放较小的对象引起的,因为失败的分配块很大。

如果您发布导致此问题的代码片段,我很乐意看一下并尝试更详细的回复。

至于发现您是否发送给所有人,请检查您的电子邮件服务器(SMTP服务器)是否写入已发送邮件的日志。如果是这样,您可以获得收到该电子邮件的人员列表。一般情况下,如果您将来发生崩溃,我建议您修改您的PHP代码以记录发送的每封电子邮件的文件或数据库。

看到代码后编辑:

从表面上看,表示电子邮件和附件的对象看起来像是一次创建并重新使用。

我建议你在本地调试代码。

首先,建立一个与生产中相同的内存限制。请尝试this resource了解具体方法。

然后,在循环中添加一些调试输出,以查看每次迭代后的memory is available

最后,在本地运行代码,但最好在您的域中替换您的电子邮件地址或已知的错误电子邮件地址(这样您就不会向人们发送垃圾邮件)。在发送过程中观察内存使用情况。

这有望帮助您缩小错误原因。

编辑2:

好的,在看到内存使用量持续增长之后,一些谷歌魔术师发现这是reported workaround的已知问题。

答案 1 :(得分:1)

除了@Malfist的回答,你可以:

  • 确保您重复使用变量,而不是为循环的每次迭代添加新变量。
  • 让系统在成功发送电子邮件时记下,并在发送一定数量的电子邮件后停止发送。下一次cron运行时,应该确定谁将被发送到并继续。

答案 2 :(得分:1)

ini_set("memory_limit","128M");

答案 3 :(得分:0)

减少内存使用量或增加内存限制。