Improve memory consumption by hiding resolver and canceller references from call stack on PHP 7+ #118
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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).