mgP*_*ePe 0 php memory memory-management cakephp fatal-error
我明白了:
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
Run Code Online (Sandbox Code Playgroud)
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'];
}
Run Code Online (Sandbox Code Playgroud)
您收到此错误的最可能原因是因为您一次处理大量数据,并且在您完成此操作后它永远不会被释放.这基本上是一个优化问题.
鉴于你有一个限制设置为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);
Run Code Online (Sandbox Code Playgroud)
在所有这些查询之间,您将新查询的子集存储在新数组中,这使我相信您的模型函数返回的数据超出了您实际需要的数量.这是代码中的一个示例:
foreach ($cus as $cu){
$uids[]=$cu['EduCourseUser']['user_id'];
}
Run Code Online (Sandbox Code Playgroud)
这是另一个似乎完全和完全没必要的,它完全可以互换使用$wt.
$writing['Writing'] = $wt['Writing'];
Run Code Online (Sandbox Code Playgroud)
最后,您$wording将其分配并分配给它$wording_sorted.我看到你将两个传递给视图,但是你是否需要同时排序和未排序的表单?我无法告诉你应该在那里做什么,但请考虑你的选择.
以下是您可以采取的措施来帮助解决其中的一些问题:
完成后销毁对数据的引用:在使用它们之后取消设置查询结果,因为它们无缘无故地占用内存.这是一对夫妇:
// after foreach($cus as $cu) { ... }
unset($cus);
// after foreach($wording as $wd) { ... }
unset($clicks);
Run Code Online (Sandbox Code Playgroud)
当然,你将其他事情传递给你的观点,所以取消这些就会破坏你的观点.
删除不必要的赋值:我已经突出显示了一个无理由分配了另一个变量的实例.我看不出不这样做的理由:
// $wt = $this->WritingTranslation->getById(...)
$writing = $this->WritingTranslation->getById(...);
// change remaining references to 'wt' to 'writing'
Run Code Online (Sandbox Code Playgroud)
确保你没有获取不相关的数据:由于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']);
}
Run Code Online (Sandbox Code Playgroud)
(我无法测试,但它应该指向正确的方向.)
这引入了更多的数据库查询,但计数器缓存字段可能会派上用场进行优化.
使你的限制更严格:你的限制设置为2000.我不知道这是非常小还是真的很高,但如果这意味着你每页显示2000个结果,只需将其减少到100以下就可以解决你的问题.问题甚至没有做任何其他事情.
如上所述,这是所有优化的东西,所以你的代码可能没有错误或破坏,只需要一些微调.