From d5b2cbefd30f9103a885f7aa843f0035b30da3a0 Mon Sep 17 00:00:00 2001 From: Alexander Pankratov <34161928+xtrime-ru@users.noreply.github.com> Date: Fri, 22 May 2020 13:30:14 +0300 Subject: [PATCH] Fix memory leaks when downloading files to callback. (#816) --- src/danog/MadelineProto/MTProto.php | 6 +- .../MadelineProto/MTProtoTools/Files.php | 10 ++-- .../MTProtoTools/GarbageCollector.php | 59 +++++++++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 src/danog/MadelineProto/MTProtoTools/GarbageCollector.php diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 256a17f5..4e7eb79d 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -22,12 +22,12 @@ namespace danog\MadelineProto; use Amp\Dns\Resolver; use Amp\File\StatCache; use Amp\Http\Client\HttpClient; -use Amp\Loop; use danog\MadelineProto\Async\AsyncConstruct; use danog\MadelineProto\Loop\Generic\PeriodicLoop; use danog\MadelineProto\Loop\Update\FeedLoop; use danog\MadelineProto\Loop\Update\SeqLoop; use danog\MadelineProto\Loop\Update\UpdateLoop; +use danog\MadelineProto\MTProtoTools\GarbageCollector; use danog\MadelineProto\MTProtoTools\CombinedUpdatesState; use danog\MadelineProto\MTProtoTools\MinDatabase; use danog\MadelineProto\MTProtoTools\ReferenceDatabase; @@ -465,6 +465,8 @@ class MTProto extends AsyncConstruct implements TLCallback yield from $this->getConfig([], ['datacenter' => $this->datacenter->curdc]); $this->startUpdateSystem(true); $this->v = self::V; + + GarbageCollector::start(); } /** * Sleep function. @@ -921,6 +923,8 @@ class MTProto extends AsyncConstruct implements TLCallback yield $this->updaters[false]->resume(); } $this->updaters[false]->start(); + + GarbageCollector::start(); } /** * Unreference instance, allowing destruction. diff --git a/src/danog/MadelineProto/MTProtoTools/Files.php b/src/danog/MadelineProto/MTProtoTools/Files.php index 670eeb53..bf2e7a72 100644 --- a/src/danog/MadelineProto/MTProtoTools/Files.php +++ b/src/danog/MadelineProto/MTProtoTools/Files.php @@ -499,7 +499,7 @@ trait Files $cb = [$bridge, 'callback']; $read = $this->uploadFromCallable($reader, $size, $mime, '', $cb, true, $encrypted); $write = $this->downloadToCallable($media, $writer, null, true, 0, -1, $chunk_size); - list($res) = yield \danog\MadelineProto\Tools::all([$read, $write]); + [$res] = yield \danog\MadelineProto\Tools::all([$read, $write]); return $res; } @@ -1038,7 +1038,7 @@ trait Files if (\count($range) == 1) { $range[1] = ''; } - list($size_unit, $range_orig) = $range; + [$size_unit, $range_orig] = $range; if ($size_unit == 'bytes') { //multiple ranges could be specified at the same time, but for simplicity only serve the first range //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt @@ -1046,7 +1046,7 @@ trait Files if (\count($list) == 1) { $list[1] = ''; } - list($range, $extra_ranges) = $list; + [$range, $extra_ranges] = $list; } else { return [ 'serve' => false, @@ -1061,7 +1061,7 @@ trait Files if (\count($listseek) == 1) { $listseek[1] = ''; } - list($seek_start, $seek_end) = $listseek; + [$seek_start, $seek_end] = $listseek; $seek_end = empty($seek_end) ? ($messageMedia['size'] - 1) : \min(\abs(\intval($seek_end)), $messageMedia['size'] - 1); @@ -1274,7 +1274,7 @@ trait Files $time = 0; $speed = 0; $origCb = $cb; - $cb = function () use ($cb, $count, &$time, &$speed) { + $cb = static function () use ($cb, $count, &$time, &$speed) { static $cur = 0; $cur++; \danog\MadelineProto\Tools::callFork($cb($cur * 100 / $count, $time, $speed)); diff --git a/src/danog/MadelineProto/MTProtoTools/GarbageCollector.php b/src/danog/MadelineProto/MTProtoTools/GarbageCollector.php new file mode 100644 index 00000000..55ee2a4d --- /dev/null +++ b/src/danog/MadelineProto/MTProtoTools/GarbageCollector.php @@ -0,0 +1,59 @@ + static::$memoryConsumption + static::$memoryDiffMb) { + gc_collect_cycles(); + static::$memoryConsumption = static::getMemoryConsumption(); + $cleanedMemory = $currentMemory - static::$memoryConsumption; + Logger::log("gc_collect_cycles done. Cleaned memory: $cleanedMemory Mb", Logger::NOTICE); + } + }); + } + + private static function getMemoryConsumption(): int + { + $memory = round(memory_get_usage()/1024/1024, 1); + Logger::log("Memory consumption: $memory Mb", Logger::VERBOSE); + return (int) $memory; + } +} \ No newline at end of file