【问题标题】:CakePHP gives me Fatal Error for exhausted memoryCakePHP 给了我内存耗尽的致命错误
【发布时间】:2012-04-20 16:47:51
【问题描述】:

我明白了:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 18635837 bytes) in /Users/[...]/cake/libs/cache/file.php on line 135

我不明白什么会消耗这么多内存。

我有很大的变量,其中包含大量的数组和数据。我的控制器就这样结束了:

// RENDER
$this->set(compact('var1', 'var2'));
debug(memory_get_usage()); // prints out: 33997240

33MB 远不及 134MB

如果我将debug(memory_get_usage()); 作为视图的第一行,我仍然会收到致命错误,这意味着问题不在视图的循环中。它似乎也不在控制器中,而是在控制器和视图之间。

如何调查问题所在并解决问题?

EDIT

function assignment_results($aid=null, $uid=null){
    if($aid==null){
        $this->Session->setFlash(__('Sorry but my butt got booted. 1907125790'));
        $this->redirect($this->Misc->redirectHome());
    }
    $assignment = $this->EduAssignment->getById($aid);
    // Get User IDS
    if($uid==null){
        $cus = $this->EduCourseUser->getStudentsForCourseId($assignment['EduAssignment']['edu_course_id']);
        foreach ($cus as $cu){
            $uids[]=$cu['EduCourseUser']['user_id'];
        }
    }else{
        $uids[]=$uid;
    }

    // GET WORDING
    $course = $this->EduCourse->getById($assignment['EduCourse']['id']);
    $wt = $this->WritingTranslation->getById($assignment['EduAssignment']['writing_translation_id']);
    $writing['Writing'] = $wt['Writing'];

    if($writing['Writing']['type']== 'song' || $writing['Writing']['type']== 'video')
        $this->paginate['limit'] = 2000;

    $wording = $this->paginate('Word', array('Word.writing_translation_id'=>$wt['WritingTranslation']['id']));
    $word_ids = array();
    foreach($wording as $w){
        $word_ids[]=$w['Word']['id'];
    }

    // CLICKS
    $this->Click->unbindModel(array('belongsTo' => array('Word' )));
    $clicks = $this->Click->getForAssignmentUserIds($assignment['EduAssignment']['id'], $uids);

    // Assign clicks to words
    foreach ($wording as &$wg){
        $num = 0;
        foreach ($clicks as $cl){
            if($wg['Word']['id']==$cl['Click']['word_id']){
                $num++;
            }
        }
        $wg['Word']['click_number'] = $num;
    }

    // List of words by how many times clicked:
    $wording_sorted = $wording;
    // echo(memory_get_usage());
    uasort($wording_sorted, array('TeachController', '_cmp'));
    // debug(memory_get_usage());

    // RENDER
    $this->set(compact('writing', 'wording','wording_sorted', 'assignment', 'course'));
    // debug(memory_get_usage());
}
function _cmp($a, $b){
    return $a['Word']['click_number']<$b['Word']['click_number'];
}

【问题讨论】:

  • 很确定你在某处看到了无限的景象。在那之前你会做什么?
  • 如果我有无限循环,它永远不会让我到达调试所在的最后一行。此外,该页面有时会设法加载,有时则不会。将函数添加为编辑,以便您可以查看代码

标签: php cakephp memory memory-management fatal-error


【解决方案1】:

您收到此错误的最可能原因是您同时处理大量数据,并且在您处理完这些数据后从未发布。这基本上是一个优化问题。

鉴于您将其中的限制设置为 2000,我假设您正在使用大型数据库,而高值可能是唯一的问题。不过,我也会强调一些其他突出的东西。

首先,请注意,您要从多个位置的数据库中获取数据。

$assignment = $this->EduAssignment->getById($aid);

$cus = $this->EduCourseUser->getStudentsForCourseId($assignment['EduAssignment']['edu_course_id']);

$course = $this->EduCourse->getById($assignment['EduCourse']['id']);

$wt = $this->WritingTranslation->getById($assignment['EduAssignment']['writing_translation_id']);

$clicks = $this->Click->getForAssignmentUserIds($assignment['EduAssignment']['id'], $uids);

在所有这些查询之间,您将查询的子集存储在新数组中,这让我相信您的模型函数返回的数据比您实际需要的数据多。这是您的代码中的一个示例:

 foreach ($cus as $cu){
     $uids[]=$cu['EduCourseUser']['user_id'];
 }

这是另一个似乎完全和完全没有必要的,它与$wt 完全互换使用。

$writing['Writing'] = $wt['Writing'];

最后,你将$wording 赋值给$wording_sorted,进行排序。我看到您将两者都传递给视图,但是您是否需要同时排序和未排序的表单?我不能告诉你应该在那里做什么,但请考虑你的选择。

您可以采取以下措施来帮助解决其中的一些问题:

用完后销毁对数据的引用:在使用完查询结果后取消设置它们,因为它们无缘无故地占用内存。这是一对:

// after foreach($cus as $cu) { ... }
unset($cus);

// after foreach($wording as $wd) { ... }
unset($clicks);

当然,您会将其他内容传递给您的视图,因此取消设置这些内容会破坏内容。

删除不必要的分配:我已经突出显示了一个实例,其中无缘无故地分配了另一个变量。我找不到不这样做的理由:

// $wt = $this->WritingTranslation->getById(...)
$writing = $this->WritingTranslation->getById(...);

// change remaining references to 'wt' to 'writing'

确保您没有获取不相关的数据:由于 Cake 格式化查询结果的方式,很难判断您正在使用什么,但如果您的模型是优化的主要目标当您只需要一两个时,它们中的方法将返回表中的所有列及其所有关联。如果可以的话,让你传递给 Cake 模型的条件更具体。

使用 Cake 的模型 count 方法:您可以在一个地方计算点击次数,方法是获取所有点击次数并使用嵌套迭代器。当你只是在一个整数之后时,你不需要很多数据。考虑创建另一个模型方法:

// Click model
function countWordClicks($word_id) {
    return $this->find('count', array('word_id' => $word_id)) ?: 0;
}

// the following thus becomes redundant
$clicks = $this->Click->getForAssignmentUserIds($assignment['EduAssignment']['id'], $uids);

foreach ($wording as &$wg){
    $num = 0;
    foreach ($clicks as $cl){
        if($wg['Word']['id']==$cl['Click']['word_id']){
            $num++;
        }
    }
    $wg['Word']['click_number'] = $num;
}
// unset($clicks);

// and can be replaced with
foreach ($wording as &$wg) {
    $wg['Word']['click_number'] = $this->Click->countWordClicks($wg['Word']['id']);
}

(我无法对此进行测试,但它应该为您指明正确的方向。)

这会引入更多的数据库查询,但计数器缓存字段可能会派上用场来优化它。

使您的限制更加严格:您的限制设置为 2000。我不知道这是真的很小还是真的很高,但如果这意味着您每显示 2000 个结果页面,只需将其减少到不到 100 个可能就可以解决您的问题,甚至无需执行任何其他操作。

如上所述,这都是优化的东西,所以你的代码可能没有错误或损坏,只是需要一些微调。

【讨论】:

    猜你喜欢
    • 2015-07-02
    • 1970-01-01
    • 2011-07-12
    • 2017-06-21
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    相关资源
    最近更新 更多