reactphp / promise

Promises/A implementation for PHP.
https://reactphp.org/promise/
MIT License
2.38k stars 146 forks source link

Improve memory consumption by cleaning up canceller function references when they are no longer needed #119

Closed clue closed 6 years ago

clue commented 6 years ago

Settling a pending Promise or Deferred means that its canceller function (if any) can no longer be invoked. By removing the reference to the canceller function in this case, we can ensure that an explicit reference back to the promise in the canceller now no longer causes a cyclic garbage reference in any exception trace as discussed in #46. This builds on top of the implementation approach in #117 and #118 and the ideas discussed in #46.

The gist here is that using a 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.

Similar patches have been introduced with #117 and #118 to implement a similar logic for the internal cancellation callbacks and this PR takes advantage of this for its internal implementation.

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 any supported PHP version 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).