php - PHPUnit coverage: Allowed memory size of 536870912 bytes exhausted
Get the solution ↓↓↓I am trying to generate code test coverage for my PHP project with PHPUnit and phpdbg using the following command:
phpdbg -dmemory_limit=512M -qrr ./bin/phpunit -c .phpunit.cover.xml
This works perfectly fine:
PHPUnit 6.2.4 by Sebastian Bergmann and contributors.
........ 8 / 8 (100%)
Time: 114 ms, Memory: 14.00MB
OK (8 tests, 13 assertions)
Generating code coverage report in HTML format ... done
However, when I use the exact same command in a docker container:
docker run -it --name YM4UPltmiPMjObaVULwsIPIkPL2bGL0T -e USER=sasan -v "/home/sasan/Project/phpredmin:/phpredmin" -w "/phpredmin" --user "1000:www-data" php:7.0-apache phpdbg -dmemory_limit=512M -qrr ./bin/phpunit -c .phpunit.cover.xml
I get the following error:
PHPUnit 6.2.4 by Sebastian Bergmann and contributors.
[PHP Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 561514763337856 bytes) in /phpredmin/vendor/phpunit/phpunit/src/Util/GlobalState.php on line 166]
I don't understand why PHPUnit needs to allocate 561514763337856 bytes of memory. I suspect it gets stuck in a loop, but why this does not happen outside of the container? Here is my PHP version on my machine:
PHP 7.0.22-0ubuntu0.17.04.1 (cli) (built: Aug 8 2017 22:03:30) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.22-0ubuntu0.17.04.1, Copyright (c) 1999-2017, by Zend Technologies
And here is the .phpunit.cover.xml file:
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
cacheTokens="false"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="true"
stopOnFailure="true"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="false">
<testsuites>
<testsuite name="PhpRedmin PHP source">
<directory>src-test/</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html" target="cover/" lowUpperBound="35"
highLowerBound="70"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src-test/</directory>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
</phpunit>
-- Edit1 --
I found that it has something to do with @runInSeparateProcess. When I remove the test that has @runInSeparateProcess then it starts to work. But still I don't know what is the problem
-- Edit2 --
Also I found out that If I don't mount my code directory in the Docker container everything works fine
Answer
Solution:
Add '-d memory_limit=-1' before your test
if use composer use the below code
./vendor/bin/simple-phpunit -d memory_limit=-1 tests/
if you use phpdbg use the below code
phpdbg -d memory_limit=-1 -qrr vendor/bin/phpunit --coverage-text
Answer
Solution:
When we use@runInSeparateProcess
, PHPUnit will attempt to serialize included files, ini settings, global variables, and constants to pass them to the new process. In this case, it looks like PHPUnit encountered a recursive scenario when serializing one of these items, which exhausted the memory available to the PHP process. We need to determine what changed between your local environment and the Docker container.
First, we can try disabling this serialization behavior to verify that we should proceed along this path. Add the following@preserveGlobalState
annotation to the test method that fails:
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testInSeparateProcess()
{
// ...
}
If this resolves the problem, or if we get a new error, we can begin looking for differences in the Docker container that may cause the issue. Without more visibility into the code and environment, it's hard to suggest where to start, but here are some ideas:
- Compare the output of
php -i
from each environment. Look out for PHP extensions that exist in one, but not the other. - Use
phpdbg
to set a breakpoint and step through the code. We're already using it to generate coverage, but it's also a useful debugging tool. We're looking for the item that causes the infinite recursion. Note that we'll need to set the breakpoint before PHPUnit executes the test case such as in the bootstrap file or PHPUnit source code (line 810 ofTestCase
may work). - When bind-mounting a volume, make sure the
www-data
user in the container has the same UID as the user that owns the files on the host. - Try running the test without the memory limitation. Obviously we can't allocate as much as the error suggests we may need, but the memory limit may mask another underlying problem. We can kill the container if needed.
I couldn't reproduce this issue using a dummy test in a similar environment (as close as I could get—same container with volume), so the code under test may contribute to the problem.
Answer
Solution:
Your mounted folder probably has all vendors and cache files. Try mounting only the source folder.
Answer
Solution:
This is phpdbg bug. Note how much memory it tries to allocate? It is insane. I tried hard to figure out where the bug exactly: if test script full name (directory + script file name) exceeds certain size then it overflows the stack (yeah, stackoverflow ;) and overwrites integer which specifies how much memory must be allocated. Then normal error handling kicks in: not enough memory to allocate such insane amount. So this is for Krakjoe to fix. Or may be I will make a patch for it in my spare time. If you need to have resolution right now: make sure that directory path your script is in is short.
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: uncaught mysqli_sql_exception
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.