Skip to content

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

@breath-co2

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions