2012-04-07 3 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

, и я не понимаю, что может поесть так много оперативной памяти.

У меня есть большие переменные с обширными массивами и данными в них. Мой контроллер заканчивается так:

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

довольно уверен, что у вас есть какой-то бесконечный вид где-то там. что вы делаете до этого? – mark

+0

Если бы у меня был бесконечный цикл, он бы никогда не довел меня до последней строки, где отладка. Кроме того, странице иногда удается загрузить, а иногда нет. Добавление функции в качестве редактирования, чтобы вы могли видеть код – mgPePe

ответ

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, для сортировки. Я вижу, что вы проходите оба вида, но вам нужно Нужно как отсортированные, так и несортированные формы в одно и то же время? Я не могу сказать вам, что вы должны там делать, но рассмотрите свои варианты.

Вот что вы можете сделать, чтобы помочь исправить некоторые из этих вопросов:

Destroy ссылки на данные, когда вы закончите с этим: UNSET результаты запроса после того, как вы использовали их, потому что они занимая память без причины. Вот пара:

// 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 method: Вы считаете клики в одном месте, выбирая их все и используя вложенные итераторы. Это много данных, которые вам не нужны, когда вы сразу после целого числа. Рассмотрим создание другой метод модели:

// 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 может решить вашу проблему, даже не делая ничего другого.

Как сказано, это все вещи оптимизации, поэтому ваш код может быть неправильным или сломанным, просто нуждаясь в некоторой тонкой настройке.

Смежные вопросы