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
[Console] avoid using huge amount of memory when formatting long exception #32736
Conversation
2f151bb
to
59f261b
Compare
Can you give us some numbers you measured about this improvement? |
Please don't judge me ‒ my exception was 1166286 (~1 MB) chars long (very very long doctrine request). Snippet : <?php
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Output\NullOutput;
require_once __DIR__.'/vendor/autoload.php';
$start = microtime(true);
$application = new Application();
$longText = str_repeat('Oh my god ! ', 100000);
$application->renderException(new \Exception($longText), new NullOutput());
echo sprintf('%d ms / %d MB', 1000*(microtime(true)-$start), memory_get_peak_usage()/1024**2).PHP_EOL; Results before (faster, but a lot of memory) : |
Thank :) --- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -1149,7 +1149,11 @@ class Application implements ResetInterface
$utf8String = mb_convert_encoding($string, 'utf8', $encoding);
$lines = [];
$line = '';
- foreach (preg_split('//u', $utf8String) as $char) {
+ $offset = 0;
+ while (preg_match('/.{1,1000}/u', $utf8String, $m, 0, $offset)) {
+ $offset += \strlen($m[0]);
+
+ foreach (preg_split('//u', $m[0]) as $char) {
// test if $char could be appended to current line
if (mb_strwidth($line.$char, 'utf8') <= $width) {
$line .= $char;
@@ -1158,6 +1162,7 @@ class Application implements ResetInterface
// if not, push current line to array and make new line
$lines[] = str_pad($line, $width);
$line = $char;
+ }
} |
Tested with Which value do you want me to apply for the patch ? |
10k is good |
81bcd3c
to
534015a
Compare
I think we're good 👍 Thanks @nicolas-grekas |
For |
534015a
to
47ffbad
Compare
Thank you @paxal. |
…ing long exception (paxal) This PR was submitted for the master branch but it was merged into the 4.4 branch instead (closes #32736). Discussion ---------- [Console] avoid using huge amount of memory when formatting long exception | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | none | License | MIT When formatting exceptions, `preg_split('//u')` is used to iterate over utf8 characters. When the exception is long, the amount of memory used is huge and can reach `memory_limit`. This PR uses a `Generator` to iterate over the string instead of splitting it, thus reducing the amount of memory. Commits ------- 47ffbad Avoid using huge amount of memory when formatting long exception
When formatting exceptions,
preg_split('//u')
is used to iterate over utf8 characters. When the exception is long, the amount of memory used is huge and can reachmemory_limit
.This PR uses a
Generator
to iterate over the string instead of splitting it, thus reducing the amount of memory.