我有一个加载大量数据的灯具,但每次都遇到此错误:
致命错误:允许的内存大小为 2147483648 字节已耗尽(已尝试( 分配 16777224 字节( /var/www/html/platform-cm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php 在第 65 行
[Symfony''Component''Debug''Exception''OutOfMemoryException] 错误: 允许的内存大小为 2147483648 字节已耗尽(尝试分配 16777224 字节(
经过一番研究,我发现了这篇文章,我读到日志记录可能是问题的原因,因为默认情况下AppKernel
debug设置为true的情况下实例化,然后SQL命令每次迭代都存储在内存中。
第一次尝试在 AppKernel
处禁用调试时运行命令如下:
doctrine:fixtures:load --no-debug
但是自从同样的错误以来,我没有得到运气。
第二次尝试是在config_dev.yml
禁用调试,但不建议这样做,因为我正在处理每个日志,但两者都不起作用。
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
# console:
# type: console
# bubble: false
# verbosity_levels:
# VERBOSITY_VERBOSE: INFO
# VERBOSITY_VERY_VERBOSE: DEBUG
# channels: ["!doctrine"]
# console_very_verbose:
# type: console
# bubble: false
# verbosity_levels:
# VERBOSITY_VERBOSE: NOTICE
# VERBOSITY_VERY_VERBOSE: NOTICE
# VERBOSITY_DEBUG: DEBUG
# channels: ["doctrine"]
所以,这就是我的灯具的样子:
class LoadMsisdn extends AbstractFixture implements OrderedFixtureInterface
{
public function getOrder()
{
return 13;
}
public function load(ObjectManager $manager)
{
$content = file_get_contents('number.txt');
$numbers = explode(',', $content);
shuffle($numbers);
foreach ($numbers as $key => $number) {
$msisdn = new Msisdn();
$msisdn->setMsisdn($number);
$msisdn->setBlocked((rand(1, 1000) % 10) < 7);
$msisdn->setOperator($this->getReference('operator-' . rand(45, 47)));
$this->addReference('msisdn-' . $key, $msisdn);
$manager->persist($msisdn);
}
$manager->flush();
}
}
如果我需要从EntityManager
禁用记录器,如何禁用记录器,如同一帖子的答案所示?
$em->getConnection()->getConfiguration()->setSQLLogger(null);
load
方法的对象管理器是实体管理器的实例(Doctrine'Common'Persistence'ObjectManager
只是实体/文档/等管理器实现的接口(。
这意味着您可以使用与问题中相同的命令来取消SQL记录器,例如。
$manager->getConnection()->getConfiguration()->setSQLLogger(null);
需要注意的一点是,DBAL 连接的默认日志记录设置%kernel.debug%
这意味着,除非您在配置中覆盖了它,否则日志记录应仅在dev
环境中进行。我可以看到您已经尝试使用 --no-debug
选项,但我只能假设,由于记录器是在容器编译期间设置的,因此它不会将其取消设置为未重建的容器。
测试用例中的 Symfony 3/4/5 方法
final class SomeTestCase extends KernelTestCase
{
protected function setUp(): void
{
$this->bootKernel('...');
// @see https://stackoverflow.com/a/35222045/1348344
// disable Doctrine logs in tests output
$entityManager = self::$container->get(EntityManagerInterface::class);
$entityManager->getConfiguration();
$connection = $entityManager->getConnection();
/** @var Configuration $configuration */
$configuration = $connection->getConfiguration();
$configuration->setSQLLogger(null);
}
}
我不确定它是否有助于解决内存限制问题,但您也可以尝试通过 YAML 配置(更舒适地(更改日志记录:
<小时 />禁用原则日志通道
(如您注释的代码(
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!doctrine"] # "!event", "!php"
<小时 />或设置自定义虚拟记录器
在services.yaml
中,设置默认原则记录器的类:
doctrine.dbal.logger:
class: App'ORM'Doctrine'DBAL'Logging'DummySQLLogger
并在doctrine.yaml
启用它:
doctrine:
dbal:
driver: 'pdo_mysql'
logging: true
自定义记录器必须实现接口Doctrine'DBAL'Logging'SQLLogger
。具体方法startQuery
和stopQuery
可以留空,以跳过日志记录;或者只是使用error_log
代替(就像我的情况一样(。
我不确定这是否会防止内存超出问题。最终增加PHP_MEMORY_LIMIT
(如果您的环境支持,则通过 env 变量,或通过 ini_set()
(。并注意使用正确的单位符号(兆字节M
,千兆字节G
(,我经常把它写错为.MB