-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Symfony 2.5 leaks memory during functional tests #11236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Have you tried to isolate the issue by running single tests and / or skipping them? |
Maybe it's related to #11221? |
@apfelbox nope, because this CssSelector cyclic object graph is there since 2.3 |
Ah, I didn't see the
Ok, in this case it's probably not (directly) related. |
I printed out the memory consumption inside the setUp() method: SF 2.4: https://gist.github.com/anonymous/757028ea2742b6e29cea Every test call the function WebTestCase::createClient(); to get a test client, and since the biggest memory gains during test execution happen within tests that instantiate multiple clients I think that the culprit could be that function. Thank you! |
Wow, ::testBackofficeTl from 64mb to 130. Maybe it'd be reasonable if you paste this method too. |
Base class: https://gist.github.com/anonymous/b82c4427829c6301cd9f I think it's more evident in AclTest because it instantiates many clients opposed to other tests that instantiate only one, but the RAM grows steadily at every test. I really can't figure out why it started happening in SF 2.5, I tried reading the commit log but I wasn't able to find anything related to this. Thank you! |
We are having the same problem. Memory usage in tests went from |
Our company has 140 functional tests on SF 2.5 and with no process isolation we have reached 3GB ram! With process isolation no memory leaks, but it takes 40 min. just to tun tests and 37 hours to run tests with coverage. |
@andreausu : if you wanna track down where exactly it happened then you could run Short tutorial is here if you aren't familiar with it: |
I did something similar, and this is the commit that introduced the memory leak: Unfortunately it's a quite large change. |
@andreausu can you confirm that if you revert Symfony to 880880b the memory leak doesn't happen? |
@webmozart could you take a look at it ? |
Any update on this? This bug is holding us back from upgrading to Symfony 2.5 |
@arthens the core dev who wrote the new validator is @webmozart and he will come back from vacation in the net few days (unless he is already back since this weekend, I don't remember). I expect to see some progress on this once he is back working on Symfony. |
Thanks for the update. |
Thank you for reporting this issue! There seems to be a memory leak in the new API of the Validator component. Before I start digging further, could you please check whether #11412 changes anything? |
Thank you or looking into this, unfortunately that commit doesn't fix the issue and I don't see any changes in the way it goes out of memory. |
Ok, thanks. If you want to help speeding up the fix, you could create a fork of symfony-standard that reproduces the memory leak. That would help me tremendously. |
Here it is: https://github.com/andreausu/symfony-standard/tree/2.5-memory-leak Just clone it and run app/run-tests.sh from the 2.5-memory-leak branch. My results: sf 880880b: Time: 7.68 seconds, Memory: 34.75Mb Thank you! |
Thank you so much! I narrowed the source of the error down to the following diff: 0946dbe...b1badea Still searching. |
Fixed in #11454. Thanks again for your test project, this was a tremendous help! |
Thank you so much Bernhard! |
This PR was merged into the 2.5 branch. Discussion ---------- [Validator] Fixed memory leak in ValidatorBuilder | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #11236 | License | MIT | Doc PR | - In 23534ca, the following code was introduced in `ValidatorBuilder::getValidator()`: ```php AnnotationRegistry::registerLoader(function ($class) { if (0 === strpos($class, __NAMESPACE__.'\\Constraints\\')) { $file = str_replace(__NAMESPACE__.'\\Constraints\\', __DIR__.'/Constraints/', $class).'.php'; if (is_file($file)) { require_once $file; return true; } } return false; }); ``` `AnnotationRegistry::registerLoader()` stores all loaders in a global array. Every time that `getValidator()` is called, a new closure is put onto the loader stack, referencing `$this` (i.e. the ValidatorBuilder) and consequently preventing the ValidatorBuilder (and its references) from being garbage-collected. The call to `registerLoader()` did not exist in 2.4 and I can't find a reason why it should be there. All tests are green without that code. I suppose I used it for debugging and then forgot to remove it again, so I'm removing it here. Commits ------- 283387a [Validator] Fixed memory leak in ValidatorBuilder
Thank you @webmozart - now I can upgrade to 2.5! |
A new tag would be welcome |
+1 for new tag |
The next 2.5 patch release is going to be released this week. |
Great |
Doctrine might be guilty for so much memory leaks. We have had this problem with our functional tests and what has helped in Symfony 2.7 is disabling logging queries in memory. Here's the code that made the magic for us: class OurTestCase extends WebTestCase
{
public function __construct($name = null, array $data = array(), $dataName = '')
{
parent::__construct($name, $data, $dataName);
if (!static::$kernel) {
static::$kernel = self::createKernel(array(
'environment' => 'test',
'debug' => true
));
static::$kernel->boot();
}
$this->container = static::$kernel->getContainer();
$this->em = $this->container->get('doctrine.orm.entity_manager');
// disabling logging sqls for memory leakage stop
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
foreach (array('monolog.logger.doctrine', 'logger') as $service) {
$logger = $this->container->get($service);
$logger->pushHandler(new \Monolog\Handler\NullHandler());
}
}
} I hope it helps |
@arturkarczmarczyk a better solution would be to disable the doctrine query logging in the |
@stof Thank you for your comment. We've modified the Here's the excerpt from our doctrine:
dbal:
driver: pdo_sqlite
path: %kernel.cache_dir%/test.db
charset: UTF8
logging: false
profiling: false |
All solutions are fine but they does not solve circular references across all loaded services. We use full container instance removal from all services using reflection:
This loop allows remove almost all services from memory without any negative impact on tests. Before out tests consumed over 1G memory - now just 200M. |
As of Symfony 2.8 this will be much easier #15185 |
@ramunasd can you check whether #15185 improves things when running your testsuite without your Reflection-based cleanup ? |
@ramunasd well, even if the all hold the container instance, this instance will be empty so it won't keep reference to services. On a side note, avoiding circular object graphs whenever possible is a good idea: destructing objects based on the refcount is more efficient than forcing the GC to enter in action to collect them |
@stof It's not perfect solution, this is only mine experiment :) I tough it could help for others like it helped me. Btw, in my case tests runs even faster with container reference clean up. |
@stof The solution @ramunasd provided works quite well. In total the memory consumption seems to be reduced, which in our case forced the CI server to throw an out of memory fatal error (PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted). With the fix we finish all tests at 132Mb. Btw, we're using a slightly adjusted version: /**
* Remove all container references from all loaded services
*/
protected function cleanupContainer($container, $exclude = ['kernel'])
{
$object = new \ReflectionObject($container);
$property = $object->getProperty('services');
$property->setAccessible(true);
$services = $property->getValue($container) ?: [];
foreach ($services as $id => $service) {
if (in_array($id, $exclude, true)) {
continue;
}
$serviceObject = new \ReflectionObject($service);
foreach ($serviceObject->getProperties() as $prop) {
$prop->setAccessible(true);
if ($prop->isStatic()) {
continue;
}
$prop->setValue($service, null);
}
}
$property->setValue($container, null);
} |
Since upgrading to symfony 2.5 I've been experiencing heavy memory leaks during the test suite execution on my application.
We're using the client provided by symfony (WebTestCase) to do functional testing of the application, we have ~300 tests with ~1800 assertions and on symfony 2.4 the whole test suite finished in about 3 minutes while consuming only ~100mb of RAM. After upgrading to symfony 2.5 the test suite goes out of memory very soon, consuming more memory at every test. Using a memory_limit of 512mb it stops at about 20%.
I tried upgrading to symfony dev-master but the issue remains.
I set phpunit's processIsolation flag to true to mitigate the problem, but the test suite is very slow when run with that flag.
I'm not the only one who experienced this problem: https://groups.google.com/forum/#!topic/symfony2/IItwqezE_PY
The text was updated successfully, but these errors were encountered: