Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony and PhpUnit memory leak

We have issues with memory leak when loading Doctrine in our phpunit tests

Starting for Symfony's documentation : http://symfony.com/doc/2.7/cookbook/testing/doctrine.html we have written this test :

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class memoryleakTest extends KernelTestCase
{
    private $em;

    protected function setUp()
    {
        self::bootKernel();

        $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager();
    }

    protected function tearDown()
    {
        parent::tearDown();

        $this->em->close();
    }

    function testEEE1()  { 
    }
    function testEEE2()  { 
    }
    function testEEE3()  { 
    }
    function testEEE4()  { 
    }
    function testEEE5()  { 
    }
    function testEEE6()  { 
    }
    function testEEE7()  { 
    }
    function testEEE8()  { 
    }
    function testEEE9()  { 
    }
    function testEEE10()  { 
    }
    function testEEE11()  { 
    }
    function testEEE12()  { 
    }
    function testEEE13()  { 
    }
    function testEEE14()  { 
    }
    function testEEE15()  { 
    }
    function testEEE16()  { 
    }
}

we got this result (php_memory_usage between parenthesis) :

testEEE1: . (42M)
testEEE2: . (42.7M)
testEEE3: . (43.3M)
testEEE4: . (44M)
testEEE5: . (44.8M)
testEEE6: . (45.5M)
testEEE7: . (46.1M)
testEEE8: . (46.8M)
testEEE9: . (47.4M)
testEEE10: . (48.1M)
testEEE11: . (48.7M)
testEEE12: . (49.4M)
testEEE13: . (50.1M)
testEEE14: . (50.7M)
testEEE15: . (51.4M)
testEEE16: . (52M)

If we remove the doctrine manager loading in setup, we got (32,7M) for each test

Is it a proper way to unload doctrine after each test in the teardown function ?

like image 808
Cedric Avatar asked Mar 16 '16 09:03

Cedric


2 Answers

The full solution as been found here: https://github.com/symfony/symfony/issues/18236

For each service used in the phpunit test, you have to free it by assigning null to the variable if you want the garbage collector to free memory.

protected function tearDown()
{
    parent::tearDown();

    $this->em->close();

    $this->em=null;

    gc_collect_cycles();
}
like image 93
Cedric Avatar answered Nov 08 '22 17:11

Cedric


To make this even easier for you, you can have a BaseTestCase.php with a teardown function and put this inside:

// Remove properties defined during the test
    $refl = new \ReflectionObject($this);
    foreach ($refl->getProperties() as $prop) {
        if (!$prop->isStatic() && 0 !== strpos($prop->getDeclaringClass()->getName(), 'PHPUnit_')) {
            $prop->setAccessible(true);
            $prop->setValue($this, null);
        }
    }

That piece of code will save you from some headaches :)

like image 37
Luis Lopes Avatar answered Nov 08 '22 16:11

Luis Lopes