2012-04-07 61 views
0

我得到:CakePHP的給了我致命錯誤的耗盡內存

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

,我不明白什麼可以吃了這麼多的RAM。

我有很大的變量,其中有廣泛的數組和數據。我控制器結束這樣的:

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

33MB無處接近134MB

如果我把debug(memory_get_usage());作爲視圖的第一行,我仍然得到的是致命錯誤,這意味着這個問題是不是在循環的看法。它似乎不在控制器中,而是在控制器和視圖之間。

我該如何調查問題所在並解決問題?

編輯<整體功能的代碼:

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']; 
} 
+0

很確定你在那裏有一些無限的外觀。你在那之前做了什麼? – mark 2012-04-07 11:44:29

+0

如果我有無限循環,它將永遠不會讓我到調試的最後一行。此外,頁面有時會加載,有時不會。添加該功能作爲編輯,以便您可以看到代碼 – mgPePe 2012-04-07 12:30:18

回答

7

你收到此錯誤最可能的原因是因爲你可以同時與大量數據的工作,它從來沒有被釋放時,你已經完成了。這基本上是一個優化問題。

考慮到你在那裏的限制設置爲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的模型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以下可能解決您的問題,甚至不需要做任何事情。

如上所述,這是所有優化的東西,所以你的代碼可能沒有錯或者被破壞,僅僅需要一些微調。

相關問題