我使用symfony2命令作为cron作业向群发成员发送批量电子邮件。
实际代码:
$output->writeln('Before: '.(memory_get_usage() / 1024 / 1024));
$mailer->send($m);
$output->writeln('After: '.(memory_get_usage() / 1024 / 1024));
我的结果:
Before: 182.38 MB
After: 183.73 MB
每次发送电子邮件时,swiftmailer都会消耗额外的1 + MB内存。这似乎并不合适,但每次发送新消息时内存都会增加。我在这里做错了吗?
答案 0 :(得分:5)
您指出的问题实际上更多的是解决方案而不是问题。你没有做错任何事,这是由于SwiftMailer内部发送电子邮件的方式。
根据send()
方法,SwiftMailer实际上并不发送任何内容,而只是将其放入他的假脱机中。默认情况下,假脱机选项为memory
,并且在内核终止之前发生假脱机刷新。所以memory_get_usage()
没有机会告诉你内存已经被释放(因为很明显,你的脚本仍在运行,并且SwiftMailer还没有刷新它的假脱机)。
来自Symfony2文档:
当您使用假脱机将电子邮件存储到内存时,它们会得到 在内核终止之前发送。这仅表示电子邮件 如果整个请求执行没有任何未处理,则会被发送 例外或任何错误。
如果此假脱机选项导致您遇到麻烦,您可以切换到File
假脱机选项。
可以通过更改此内容来完成:
# app/config/config.yml
swiftmailer:
# ...
spool: { type: memory }
对此:
# app/config/config.yml
swiftmailer:
# ...
spool:
type: file
path: /path/to/spool
然后,您可以将cron作业配置为自动并定期刷新假脱机:
$ php app/console swiftmailer:spool:send --env=prod
或者,您可以选择根本不使用假脱机系统,这意味着您在执行脚本期间将发送所有电子邮件。它可以帮助您摆脱内存问题,但可能会损害您的用户,具体取决于您是否在请求页面时发送邮件。但是,正如你在cron工作中所做的那样,在你的情况下它肯定不会是一个问题。可能是有一天。
答案 1 :(得分:5)
我在使用swiftmailer发送电子邮件时遇到了类似的内存问题。似乎插件会创建这些内存泄漏,因此不必删除事件调度程序代码,只需禁用插件(对于您的情况,使用您自己的解决方案进行修补)。
使用simfony2,在配置中轻松禁用日志记录:
swiftmailer:
logging: false
或使用多个邮寄者:
swiftmailer:
mailers:
my_mailer:
logging: false
在我的情况下,发送~1500封电子邮件,内存增长到大约100MB(仅仅因为记录器),现在> 0.2MB。
我知道这有点晚了,但也许这对遇到同样问题的人有用。 : - )
答案 2 :(得分:-1)
编辑:不确定为什么用户正在进行投票。事实是swiftmailer本身有一个与其事件/插件系统直接相关的内存泄漏。当钩子被执行时,它会占用永远不会释放的内存。仅仅删除事件系统就可以修复内存泄漏,而不会破坏swiftmailer在实际发送电子邮件时的工作方式。
我解决了这个问题。我编辑了MailTransport类并删除了swiftmailer中的事件系统。我只允许构建和发送消息本身,没有前后插件废话。
我从throttlerplugin中获取了部分并由自己的版本创建,它专门只处理每分钟的消息:
class EmailThrottler {
private $startTime;
private $messagesPerMinute;
private $_messages;
public function __construct($messagesPerMinute = 25)
{
$this->startTime = time();
$this->messagesPerMinute = $messagesPerMinute;
$this->_messages = 0;
}
public function run()
{
$this->_messages++;
$duration = time() - $this->startTime;
$sleep = $this->_throttleMessagesPerMinute($duration);
if ($sleep > 0) {
sleep($sleep);
}
}
private function _throttleMessagesPerMinute($duration)
{
$expectedDuration = $this->_messages / ($this->messagesPerMinute / 60);
return (int) ceil($expectedDuration - $duration);
}
}
我在邮件循环之前初始化了我的自定义throttler类:
$throttler = new EmailThrottler($pendingCampaign->getRateLimit());
我在每封发送的电子邮件后运行它:
$mailer->send($m);
$throttler->run();
希望他们能找到对事件系统的修复。无论如何,我会看看5.4的表现是否有任何不同,但对于那些在5.3上的人来说这个解决方案我只是在5.3上为我工作了
干杯:)