Skip to content

form: CachingFactoryDecorator consumes unbounded amounts of memory #29259

Closed
@pschultz

Description

@pschultz

Symfony version(s) affected: >= 2.7

Description
CachingFactoryDecorator has no bounds on its caches, leading to excessive memory usage.

One of our console commands builds several thousand form instances to generate a sitemap (the query strings are inferred from the form values).

Because the CachingFactoryDecorator holds on to every choice list ever built, the command's memory usage easily exceeds 500 MB. The problem goes away by changing the form.choice_list_factory from form.choice_list_factory.cached (the hard coded default) to form.choice_list_factory.default:

services:
    form.choice_list_factory: '@form.choice_list_factory.default'

How to reproduce
Run the following console command and watch the memory usage increase forever:

<?php

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FormType;

class EatMemoryCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('eat-memory')
            ->setDescription('Consumes all available memory by repeatedly building forms')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $formFactory = $this->getApplication()->getKernel()->getContainer()->get('form.factory');

        $progress = new ProgressBar($output);
        $progress->setFormat('%current% / memory usage: %memory% ');
        $progress->setRedrawFrequency(1e3);

        for (;;) {
            $builder = $formFactory->createBuilder(FormType::class, [], []);
            $builder->add('foo', ChoiceType::class, [
                'choices' => [ 'bar' => 'baz', ],
            ]);
            $builder->getForm();

            $progress->advance();
        }
    }
}

Possible Solution
CachingFactoryDecorator should limit the lengths of its lists and views properties.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions