Symfony 和 PhpUnit 内存泄漏

Symfony and PhpUnit memory leak

我们在 phpunit 测试中加载 Doctrine 时遇到内存泄漏问题

开始阅读 Symfony 的文档: http://symfony.com/doc/2.7/cookbook/testing/doctrine.html 我们已经编写了这个测试:

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()  { 
    }
}

我们得到了这个结果(括号之间的php_memory_usage):

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)

如果我们在设置中删除学说管理器加载,我们会为每个测试得到 (32,7M)

在拆解函数中每次测试后卸载 doctrine 是正确的方法吗?

在这里找到完整的解决方案: https://github.com/symfony/symfony/issues/18236

对于 phpunit 测试中使用的每个服务,如果您希望垃圾收集器释放内存,您必须通过将 null 分配给变量来释放它。

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

    $this->em->close();

    $this->em=null;

    gc_collect_cycles();
}

为了让这对你来说更容易,你可以有一个带有拆卸功能的 BaseTestCase.php 并把它放在里面:

// 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);
        }
    }

这段代码会让你免于一些头痛:)