Clear memory being used by PHP

后端 未结 4 632
清歌不尽
清歌不尽 2021-02-05 21:54

I\'m running into an interesting problem. I\'m using PHPUnit, and my tests take more memory every single time I run them. Ie...

2.25 MB

2.5 MB

3.0 MB

相关标签:
4条回答
  • 2021-02-05 22:23

    Calvin, as per discussed in the chat, it was due to missing reset features.

    When testing, we must ensure that the test environment is consistent so that we're able to get accurate results. Computing is Input/Output and hence we should use Fixtures in PHPUnit to reset storage to prevent "memory leaks" like these.

    0 讨论(0)
  • 2021-02-05 22:25

    The memory increase has three to four reasons:

    1) PHPUnit collects code coverage data

    There is nothing you can do about this except turn off code coverage.

    2) PHPUnit caches file tokens for code coverage

    You can use <phpunit cacheTokens="false"> in your PHPUnit xml. See the note about this in http://phpunit.de/manual/current/en/installation.html#installing.upgrading

    3) PHPUnit doesn't properly clean up after itself

    In its current implementation it keeps the test cases around because thats where the result data is stored. In the future this will be changed to be more efficent but for now it's how things works.

    4) Leading to "4": You need to clean up after your self too

    Since the TestCase instances are keep around your member variables are kept around too.

    Meaning you can save a lot of memory by using

    public function tearDown() {
        unset($this->whatever);
    }
    

    but doing so is very tedious.

    My suggestion is to have a base test class for all your TestCases and use this:

    class MyBaseTest extends \PHPUnit_Framework_TestCase {
    
        protected function tearDown()
        {
            $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);
                }
            }
        }
    }
    

    This will clean up after you in a nice, automated way.

    (props for the snippet go to: http://kriswallsmith.net/post/18029585104/faster-phpunit)


    PHPUnit can't do this in a backwards compatible way that wouldn't break people's projects so you have to add it for you own :)

    0 讨论(0)
  • 2021-02-05 22:29

    If you are using PDO (or similar database abstraction), then you can use "sqlite::memory:" as you DSN. This has three great advantages:

    1. Automatic clear-up after each test
    2. No chance of accidentally touching a production DB (e.g. even when you run your unit tests on your production server).
    3. All in memory, so tests may run quicker

    The disadvantage is that your SQL has to be portable between MySQL and SQLite. This might turn out to be quite a lot of work (For bigger projects it is often worth it, not just for tests, but for the way it will improve your code's design.) In your case ou mention using Doctrine, in the chat transcript, so you may already have a good abstraction, and therefore it may just run with no changes on SQLite.

    0 讨论(0)
  • 2021-02-05 22:31

    The technical details behind PHPUnit's garbage collection have already been covered by @edorian and @mauris, but I wanted to add that PHPUnit (at least in version 3.7.21, which I'm running) gives you the ability to add the comment:

    /**
     * @backupGlobals disabled
     */
    class MyClassTests extends PHPUnit_Framework_TestCase{}
    

    Before adding the annotation, I was roughly doubling my memory usage on each run of my test suite, the last one hitting about 1100 MB. Now they're running at 15 MB.

    0 讨论(0)
提交回复
热议问题