-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Process] Unset callback after stop to free memory #16798
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
Conversation
@@ -801,6 +801,8 @@ public function stop($timeout = 10, $signal = null) | |||
$this->close(); | |||
} | |||
|
|||
$this->callback = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment explaining why it is done
this should also be reset at the end of a normal run (i.e. without the user stopping the process), as the callback won't be necessary anymore either (basically, the same benchmark without the call to |
And I think this can break the call to |
@stof unsetting the callback automatically after I am sure that it does not break anything where I put it because:
My tests on unsetting the callback in any other context other then |
I think the callback should also be reset in |
@nicolas-grekas only after pipes are close you can be sure to unset the callback, and the pipes are closed only in stop: https://github.com/symfony/process/blob/v3.0.0/Process.php#L1356 |
The line you linked doesn't proves anything about what stop does that wait doesn't do. And in fact, as far as I read correctly, wait waits for isRunning to be false, which means pipes are closed. Or did I read too quickly? |
@nicolas-grekas your assumptions are based on the ability of PipesInterface::readAndWrite $close flag to close the Pipes. What I read in the interface (https://github.com/symfony/process/blob/v3.0.0/Pipes/PipesInterface.php#L43) is "Whether to close pipes if they've reached EOF" which means is not mandatory to close the pipes with the flag activated. |
@Slamdunk let me give you my understanding of the code:
readPipes is not part of this closing procedure (it happens earlier in the call chain) |
Btw, this means that resetting the callback should be done only in the |
👍 for merging on 2.3 |
👍 |
Thank you @Slamdunk. |
…dunk) This PR was submitted for the master branch but it was merged into the 2.3 branch instead (closes #16798). Discussion ---------- [Process] Unset callback after stop to free memory | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - As of yet, a `Process` instance can't free memory. The built-in callback has a self-reference to the intance not cleared after instance destruction. I've tried to change both `buildCallback` and https://github.com/symfony/process/blob/v2.7.6/Process.php#L1373 usage to avoid self-referencing, but it can't be done without breaking BC, and the memory issue is still there. A simple test script (that obiously can't be embedded in unit-tests) ```php for ($inc = 0; $inc < 10000; $inc++) { $process = new Symfony\Component\Process\Process('echo 1'); $process->mustRun(); $process->stop(); unset($process); echo (memory_get_usage(true) / 1000000) . ' MB ' . $inc . PHP_EOL; } ``` Before: ``` 1.572864 MB 0 5.505024 MB 9999 ``` After: ``` 1.572864 MB 0 1.572864 MB 9999 ``` Ok, in this simple scenario 4 MB of RAM is nothing, but in our business app full of IOC where `unset`-ting is hard, our RAM explodes. After `stop()`, the callback is no longer necessary. To be clear, the garbage collector in the previous example was already active. Deactivating it manually, which somewhere is needed to avoid particluar segfaults, obiously leads to worse scenarios: Before: ``` gc_disable(); 1.572864 MB 0 29.360128 MB 9999 ``` After: ``` gc_disable(); 1.572864 MB 0 1.572864 MB 9999 ``` Commits ------- ec93b9a [Process] Unset callback after stop to free memory
As of yet, a
Process
instance can't free memory.The built-in callback has a self-reference to the intance not cleared after instance destruction.
I've tried to change both
buildCallback
and https://github.com/symfony/process/blob/v2.7.6/Process.php#L1373 usage to avoid self-referencing, but it can't be done without breaking BC, and the memory issue is still there.A simple test script (that obiously can't be embedded in unit-tests)
Before:
After:
Ok, in this simple scenario 4 MB of RAM is nothing, but in our business app full of IOC where
unset
-ting is hard, our RAM explodes.After
stop()
, the callback is no longer necessary.To be clear, the garbage collector in the previous example was already active.
Deactivating it manually, which somewhere is needed to avoid particluar segfaults, obiously leads to worse scenarios:
Before:
After: