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

Improve memory consumption by hiding resolver and canceller references from call stack on PHP 7+ #118

Merged
merged 2 commits into from
May 6, 2018

Conversation

clue
Copy link
Member

@clue clue commented May 4, 2018

The resolver and canceller callbacks passed to the Promise constructor are often implicitly bound to object instances or use explicit object references. If either of these functions create an Exception, these callbacks and their attached references implicitly end up in the call stack created by this exception.

This PR ensures that these callbacks are explicitly overwritten before invocation so that the call stack no longer causes a cyclic garbage reference in PHP 7+ only as discussed in #46. This builds on top of the work done in #113 and #117. If you use a static callable, this PR has no effect (also no performance or memory penalty).

The gist here is that using a resolver or canceller that has an implicit reference to the promise (quite common due to closures bindings) now no longer causes a cyclic garbage reference in any exception trace and consumers of this package do not need to take special care of this.

Note that reassigned arguments only show up in the stack trace in PHP 7, so we can't avoid this on legacy PHP. As an alternative, consumers of this package are still suggested to consider explicitly unsetting any references before throwing. A somewhat related patch has been introduced with #117, but for the child cancellation handler only. This means that this library does not cause any memory issues on its own and now has an elaborate test suite to test for these.

Invoking the benchmarking example from #113 shows no effect, as reassigning variables is a rather cheap operation. In fact, explicitly adding some bogus references to this example shows a very significant performance and memory improvement! Initially this peaked somewhere around 8 MB on my system taking 7.3s. After applying this patch, this script reports a constant memory consumption of around 0.6 MB taking 1.9s.

This PR actually includes a test that shows how garbage memory references are no longer an issue in PHP 7 only and how explicitly using references no longer causes any such references on its own (this means that this requires no effort on the consumer side).

@WyriHaximus WyriHaximus merged commit e521e57 into reactphp:2.x May 6, 2018
@clue clue deleted the stack branch May 6, 2018 09:29
jsor added a commit to jsor-labs/pact that referenced this pull request May 16, 2018
This incorporates the work done by @clue in the following PR's for reactphp/promise:

* reactphp/promise#115
* reactphp/promise#116
* reactphp/promise#117
* reactphp/promise#118
* reactphp/promise#119

Co-authored-by: Christian Lück <christian@lueck.tv>
jsor added a commit to jsor-labs/pact that referenced this pull request May 16, 2018
This incorporates the work done by @clue in the following PR's for reactphp/promise:

* reactphp/promise#113
* reactphp/promise#115
* reactphp/promise#116
* reactphp/promise#117
* reactphp/promise#118
* reactphp/promise#119

Co-authored-by: Christian Lück <christian@lueck.tv>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants