Fix memory leaks when downloading files to callback. (#816)

This commit is contained in:
Alexander Pankratov 2020-05-22 13:30:14 +03:00 committed by GitHub
parent 83802fe944
commit d5b2cbefd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 6 deletions

View File

@ -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.

View File

@ -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));

View File

@ -0,0 +1,59 @@
<?php
namespace danog\MadelineProto\MTProtoTools;
use Amp\Loop;
use danog\MadelineProto\Logger;
class GarbageCollector
{
/**
* Ensure only one instance of GarbageCollector
* when multiple instances of MadelineProto running.
* @var bool
*/
public static bool $lock = false;
/**
* How often will check memory
* @var int
*/
public static int $checkIntervalMs = 1000;
/**
* Next cleanup will be triggered when memory consumption will increase by this amount
* @var int
*/
public static int $memoryDiffMb = 1;
/**
* Memory consumption after last cleanup
* @var int
*/
private static int $memoryConsumption = 0;
public static function start(): void
{
if (static::$lock) {
return;
}
static::$lock = true;
Loop::repeat(static::$checkIntervalMs, static function() {
$currentMemory = static::getMemoryConsumption();
if ($currentMemory > 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;
}
}