Skip to content

协程的底层有一处写的有问题,会出现内存溢出 #48

Description

@breath-co2

文件 https://github.com/zanphp/coroutine/blob/master/src/Task.php 第50行如下:

 public function __construct(\Generator $coroutine, Context $context = null, $taskId = 0, Task $parentTask = null)
    {
        $this->coroutine = $this->caughtCoroutine($coroutine);
        $this->taskId = $taskId ? $taskId : TaskId::create();
        $this->parentTask = $parentTask;
        if ($context) {
            $this->context = $context;
        } else {
            $this->context = new Context();
        }
        $this->scheduler = new Scheduler($this);
    }

这个 $this->scheduler = new Scheduler($this); 这个会把 Scheduler 放在自己的寄存器里,然而 Scheduler 这个对象又把 Task 放在了自己的 task 变量里。形成了相互引用。在处理完毕后并不会释放对象,只有在php垃圾回收机制下才会被清理。不信的话,可以加

    public function __destruct()
    {
        echo "i'm unset";
    }

会发现并未协程执行完毕后这个方法并未被执行,内存中还存在。

建议Task中加:

    public function release()
    {
        # 移除对象,避免相互引用导致的对象不可释放
        if (isset($this->scheduler))
        {
            $this->scheduler->release();
            unset($this->scheduler);
        }
    }

Scheduler 中加:

    public function release()
    {
        unset($this->task);
    }

并在 Signal::TASK_KILLEDSignal::TASK_DONE 时调用。这样在协程处理完毕后,会立即释放对象,避免内存溢出。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions