1
0
mirror of https://github.com/danog/amp.git synced 2024-12-03 09:57:51 +01:00

Fixed memory leak in CombinedCancellationToken (#384)

Co-authored-by: Artur Khasanov <ah@self.team>
This commit is contained in:
Aaron Piotrowski 2022-02-20 12:33:37 -06:00
parent d05b7d56e9
commit f38e756a3d
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
2 changed files with 53 additions and 6 deletions

View File

@ -11,22 +11,28 @@ final class CompositeCancellation implements Cancellation
private string $nextId = "a";
/** @var \Closure(CancelledException)[] */
/** @var array<string, \Closure(CancelledException): void> */
private array $callbacks = [];
private ?CancelledException $exception = null;
public function __construct(Cancellation ...$cancellations)
{
foreach ($cancellations as $cancellation) {
$id = $cancellation->subscribe(function (CancelledException $exception): void {
$this->exception = $exception;
$thatException = &$this->exception;
$thatCallbacks = &$this->callbacks;
foreach ($this->callbacks as $callback) {
foreach ($cancellations as $cancellation) {
$id = $cancellation->subscribe(static function (CancelledException $exception) use (
&$thatException,
&$thatCallbacks
): void {
$thatException = $exception;
foreach ($thatCallbacks as $callback) {
EventLoop::queue($callback, $exception);
}
$this->callbacks = [];
$thatCallbacks = [];
});
$this->cancellations[] = [$cancellation, $id];

View File

@ -0,0 +1,41 @@
<?php
namespace Cancellation;
use Amp\CompositeCancellation;
use Amp\DeferredCancellation;
use Amp\PHPUnit\AsyncTestCase;
use function Amp\delay;
class CompositeCancellationTest extends AsyncTestCase
{
private const LOOP_COUNT = 20;
private const TOKENS_COUNT = 1000;
public function testBenchmark(): void
{
$firstMemoryMeasure = 0;
for ($i = 0; $i < self::LOOP_COUNT; $i++) {
$tokens = [];
for ($j = 0; $j < self::TOKENS_COUNT; $j++) {
$tokens[] = (new DeferredCancellation())->getCancellation();
}
$combinedToken = new CompositeCancellation(...$tokens);
if (!$firstMemoryMeasure && $i > self::LOOP_COUNT / 2) {
// Warmup and store first memory usage after 50% of iterations
$firstMemoryMeasure = \memory_get_usage(true);
}
// Remove tokens from memory
unset($combinedToken);
delay(0.001); // Tick loop to allow resources to be freed.
// Asserts
if ($firstMemoryMeasure > 0) {
self::assertEquals($firstMemoryMeasure, \memory_get_usage(true));
}
}
}
}