Php Yii NestedSetBehavior内存使用率

Php Yii NestedSetBehavior内存使用率,php,memory-management,yii,model,Php,Memory Management,Yii,Model,我在项目中使用NestedSetBehavior模型扩展,将db表用作树 我写了一个例子: $model = SiteMap()->findAll(); $log .= $this->debug_memory('used')."<br>"; $ancestors = null; foreach ($model as $item) { $ancestors = $item->ancestors()->findAll

我在项目中使用NestedSetBehavior模型扩展,将db表用作树

我写了一个例子:

    $model = SiteMap()->findAll();
    $log .= $this->debug_memory('used')."<br>";
    $ancestors = null;
    foreach ($model as $item) {
        $ancestors = $item->ancestors()->findAll();
    }
    $log .= $this->debug_memory('used')."<br>";
    echo $log;
经过简单计算-内存使用增加了5,24 Mb

但是我必须使用$item->祖先()->findAll();循环多次,所以我的内存增加了138MB。我得到了“内存不足错误”

我尝试使用unset():

行为函数源是:

public function ancestors($depth=null)
{
    $owner=$this->getOwner();
    $db=$owner->getDbConnection();
    $criteria=$owner->getDbCriteria();
    $alias=$db->quoteColumnName($owner->getTableAlias());

    $criteria->mergeWith(array(
        'condition'=>$alias.'.'.$db->quoteColumnName($this->leftAttribute).'<'.$owner->{$this->leftAttribute}.
            ' AND '.$alias.'.'.$db->quoteColumnName($this->rightAttribute).'>'.$owner->{$this->rightAttribute},
        'order'=>$alias.'.'.$db->quoteColumnName($this->leftAttribute),
    ));

    if($depth!==null)
        $criteria->addCondition($alias.'.'.$db->quoteColumnName($this->levelAttribute).'>='.($owner->{$this->levelAttribute}-$depth));

    if($this->hasManyRoots)
    {
        $criteria->addCondition($alias.'.'.$db->quoteColumnName($this->rootAttribute).'='.CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount);
        $criteria->params[CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount++]=$owner->{$this->rootAttribute};
    }

    return $owner;
}
公共函数祖先($depth=null)
{
$owner=$this->getOwner();
$db=$owner->getDbConnection();
$criteria=$owner->getDbCriteria();
$alias=$db->quoteColumnName($owner->getTableAlias());
$criteria->mergeWith(数组)(
'条件'=>$alias.'.$db->quoteColumnName($this->leftAttribute)。'.$owner->{$this->rightAttribute},
'order'=>$alias.'.$db->quoteColumnName($this->leftAttribute),
));
如果($depth!==null)
$criteria->addCondition($alias.'..$db->quoteColumnName($this->levelAttribute)。'>='($owner->{$this->levelAttribute}-$depth));
如果($this->hasManyRoots)
{
$criteria->addCondition($alias.'.$db->quoteColumnName($this->rootAttribute)。'='.CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount);
$criteria->params[CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount++]=$owner->{$this->rootAttribute};
}
返回$owner;
}

所以,我的问题是,为什么这个函数使用了这么多内存,为什么我取消设置变量内存时没有清理?

注释掉
protected/config/main.php
文件中的日志记录。(或者在定义配置设置的任何地方)

您看到的可能是每个活动记录调用上写入的所有日志的结果,这可以解释为什么取消设置对象不会释放内存:使用的内存不在模型中,而是在日志中

试试看并报告结果。

回答 禁用日志(正如@willem renzema已经说过的)以防止它使用内存(特别是在测试泄漏时)总是好的

但是,您应该在示例代码中的每个祖先上调用
detachBehaviors()
,以防止内存泄漏。在对每个具有附加行为的对象实例使用
unset
之前,最好先对其执行此操作,以防止发生内存泄漏。即使您没有明确地“unsetting”“对象(例如,您的变量正在移出范围)

有关此问题的更多信息,请参阅NestedSetBehavior

有关PHP和Yii中内存泄漏和循环引用的更一般性的讨论,请参见


注 您可能会尝试使用析构函数(
\uu destruct()
)来处理行为的分离但在这种特定情况下,这将不起作用,因为

“对象只会释放其资源并触发
\uuuu destruct()
方法,当所有引用都未设置时。即使 都在物体里……叹气!——(氮氧化物在奥雷贡市,2009年)


仅在“祖先”上使用
unset
无法满足此规则,因为嵌套的SetBehavior仍然有一个对存储在名为:
$\u cached
的静态数组中的“祖先”实例的引用。只有通过销毁NestedSetBehavior实例本身才能清除此引用,这将发生在您对该行为的“所有者”对象调用
detachBehaviors()
时。

您的“祖先”表上是否有一个索引,引用放置在单个表中的“项目”表PK?树,表中有这些重要的行:id | root | lft | rgt | level,id-它是自动递增的主键,root-元素父根的id,level-tree中的deeps,lft和rgt字段帮助知道哪个元素在任何给定元素的左侧和右侧。
    $model = SiteMap()->findAll();
    $log .= $this->debug_memory('used')."<br>";
    $ancestors = null;
    foreach ($model as $item) {
       $ancestors= $item->ancestors()->findAll();
    }
    $ancestors = null;
    unset($ancestors);
    $log .= $this->debug_memory('used')."<br>";
    echo $log;
used: 10525984
used: 15893320
public function ancestors($depth=null)
{
    $owner=$this->getOwner();
    $db=$owner->getDbConnection();
    $criteria=$owner->getDbCriteria();
    $alias=$db->quoteColumnName($owner->getTableAlias());

    $criteria->mergeWith(array(
        'condition'=>$alias.'.'.$db->quoteColumnName($this->leftAttribute).'<'.$owner->{$this->leftAttribute}.
            ' AND '.$alias.'.'.$db->quoteColumnName($this->rightAttribute).'>'.$owner->{$this->rightAttribute},
        'order'=>$alias.'.'.$db->quoteColumnName($this->leftAttribute),
    ));

    if($depth!==null)
        $criteria->addCondition($alias.'.'.$db->quoteColumnName($this->levelAttribute).'>='.($owner->{$this->levelAttribute}-$depth));

    if($this->hasManyRoots)
    {
        $criteria->addCondition($alias.'.'.$db->quoteColumnName($this->rootAttribute).'='.CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount);
        $criteria->params[CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount++]=$owner->{$this->rootAttribute};
    }

    return $owner;
}