Skip to content
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

[9.x] Avoid memory leak in HandleExceptions during repeated Application startup #44293

Conversation

olsavmic
Copy link

@olsavmic olsavmic commented Sep 25, 2022

Partially resolves #44214.

Repeatedly running following script (which happens during PHPUnit test setup) slowly but steadily leaks memory since the register_shutdown_function is never released:

<?php

namespace Tests\Feature;

require_once __DIR__. '/../../vendor/autoload.php';

use App\Exceptions\Handler;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Foundation\Application;

function createApplication()
{

    $app = new Application(
        $_ENV['APP_BASE_PATH'] ?? dirname(dirname(__DIR__))
    );

    $app->singleton(
        \Illuminate\Contracts\Http\Kernel::class,
        \App\Http\Kernel::class
    );

    $app->singleton(
        Kernel::class,
        \App\Console\Kernel::class
    );

    $app->singleton(
        ExceptionHandler::class,
        Handler::class
    );

    $app->make(Kernel::class)->bootstrap();

    return $app;
}

for ($i = 1; $i < 10000; ++$i) {
    createApplication()->flush();
    Artisan::forgetBootstrappers();
    Queue::createPayloadUsing(null);
    HandleExceptions::forgetApp();
    gc_collect_cycles();

    dump('Using ' . ((int) (memory_get_usage(true) / (1024 * 1024))) . 'MB in ' . $i . ' iterations.');
}

@olsavmic olsavmic force-pushed the olsavmic-avoid-memory-leak-in-handle-exceptions branch 4 times, most recently from b1ec0cf to 510fd2e Compare September 25, 2022 11:34
@olsavmic olsavmic mentioned this pull request Sep 25, 2022
@olsavmic olsavmic force-pushed the olsavmic-avoid-memory-leak-in-handle-exceptions branch from 510fd2e to 0bce18c Compare September 25, 2022 11:50
@olsavmic olsavmic changed the title Avoid memory leak in HandleExceptions during repeated Application startup [9.x] Avoid memory leak in HandleExceptions during repeated Application startup Sep 25, 2022
@olsavmic olsavmic changed the title [9.x] Avoid memory leak in HandleExceptions during repeated Application startup [9.x] WIP: Avoid memory leak in HandleExceptions during repeated Application startup Sep 25, 2022
@olsavmic olsavmic changed the title [9.x] WIP: Avoid memory leak in HandleExceptions during repeated Application startup [9.x] Avoid memory leak in HandleExceptions during repeated Application startup Sep 25, 2022
if (! static::$globalShutdownFunctionRegistered) {
static::$globalShutdownFunctionRegistered = true;

register_shutdown_function($this->forwardsTo('handleShutdown'));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not ideal as it keeps reference to original $this but there is no way to unregister a shutdown function. To solve it properly, yet another layer of indirection with reference to $this must be kept static (which pretty much makes the HandleExceptions class a singleton, which it already pretty much is 🤷‍♂️).

Needs a bit more thought.

@olsavmic olsavmic changed the title [9.x] Avoid memory leak in HandleExceptions during repeated Application startup [9.x] WIP: Avoid memory leak in HandleExceptions during repeated Application startup Sep 25, 2022
@olsavmic olsavmic force-pushed the olsavmic-avoid-memory-leak-in-handle-exceptions branch 4 times, most recently from 744ceab to 6dda8c0 Compare September 25, 2022 16:17
@olsavmic olsavmic force-pushed the olsavmic-avoid-memory-leak-in-handle-exceptions branch from 6dda8c0 to 6db4dbf Compare September 25, 2022 16:18
@olsavmic olsavmic changed the title [9.x] WIP: Avoid memory leak in HandleExceptions during repeated Application startup [9.x] Avoid memory leak in HandleExceptions during repeated Application startup Sep 25, 2022
@olsavmic
Copy link
Author

olsavmic commented Sep 25, 2022

Not a bullet-proof solution but it keeps the API, the behavior with PHPUnit should remain the same while the leak seems to be gone.

The only issue is that the handleShutdown is potentially broken in tests as it holds a reference to the old $this. it could be solved by keeping a reference to $this in a static variable (singleton) but I don't think it's actually needed.

I understand that since the leak is pretty small, the changes here may not be worth it. The current behaviour leads people to look for bugs in the framework though and not their apps so perhaps that could be prevented.

@nunomaduro nunomaduro marked this pull request as draft September 26, 2022 13:54
@nunomaduro
Copy link
Member

Closing this pull request for the reasons already mentioned here: #40656.

TL DR: You can't safely restore any of those handlers (at least on the way you are), as they may be used on vendors (such as PHPUnit, and error handler drivers), and by calling any of those restores, you don't know exactly what you are restoring. In addition, leaking a small closure is not what causing the memory exhausted cases we've seen in past issues. The $app instance on the HandleExceptions is already static, and gets destroyed between tests - assuming that does not get leaked anywhere else in people's applications.

@nunomaduro nunomaduro closed this Sep 26, 2022
@jbrooksuk jbrooksuk self-assigned this Sep 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Possible memory leak
3 participants