最近做一个导入大文件,因为涉及到要对文件处理得到需要的结构的数据。
把大量数据保存在数组中。
在处理的过程中,消耗很大内存,不是memory_limit设置问题,我已经设置足够大。
处理过程中自己也有unset掉不要的。但是通过memory_get_usage()输出函数调用前跟调用后的内存对比。
发现函数调用后,内存并没有明显的下降。那些大数组都已经unset掉了。也是一样。
如果导入的文件量不大,不会出现内存溢出的错误提示。但是当文件大到一定程度。就因为执行过程中,
函数调用完,内存还是占用很大。而导致内存溢出。
这个让我有点郁闷了。函数调用完不是都释放了局部变量空间了吗?
是不是什么内存泄露,有人遇到相同问题吗。希望有遇到相同问题的或者有人知道的。一起来讨论下。谢谢。
ps:分数蛮少的,只能这样了。

解决方案 »

  1.   

    unset()的是数组还是数组元素?
      

  2.   

    嗯 这些我都考虑了
    unset是数组
    我也知道 函数里unset()全局变量
    只是消除函数里面那个临时变量
    我都有把全局$GLOBALS 变量给unset 
    还是如此 
    以前做的东西没出过类似问题,因为之前没处理过这样大的数据。
    现在遇到这样的问题,让我重新思考这个问题。
    今天还看了 PHP内存管理的原理了
    不知道是否有人也遇到过
      

  3.   

    代码太长了,我贴一个函数吧function importTestSuiteFormArray1($db,$parentID,$tproject_id,$userID,$duplicateLogic,&$testsuiteArray,&$testcaseArray){
    global $productIndex;
    $unexistPF = array();//用于存放当前项目中没有的excel文件存在的平台
    $produceRelFB = array();
    $resultMap = null;
    $tsResult = null;//测试套件导入结果
    $tables = tlObject::getDBTables("platforms");
    $pfSql = " select id,name from ".$tables['platforms']." where testproject_id=$tproject_id";
    $pfRe = $db->fetchColumnsIntoMap($pfSql,"id","name");
    $pfRe = is_null($pfRe) ? array() : $pfRe;
    foreach($productIndex as $vKey=>$pItem){
    if(!in_array($vKey, $pfRe)){
    $unexistPF[] = $vKey;
    }
    }
    // $memory1 = memory_get_usage();
    // $fileName = date("md-His");
    // $hand = fopen("e:/testcase/".$fileName.".txt","a+");
    // $bTime = microtime_float();
    $tempTSArray = array();
    $createSuc = "创建成功。";
    $updateSuc = "更新成功。";
    if(is_array($testsuiteArray) && count($testsuiteArray)>0){
    foreach($testsuiteArray as $key=>$tsItem){
    // $begin = microtime_float();
    if ($tsItem['name'] != "")
    {
    if($tsItem['parentNum']==0){
    $parID = $parentID;
    }else{
    $parID = $tempTSArray[$key]['parentID'];
    }
    $tsuiteMgr = new testsuite($db);
    $info = $tsuiteMgr->get_by_name($tsItem['name'],$parID);
    if( is_null($info) )
    {
    $ret = $tsuiteMgr->create($parID,$tsItem['name'],"",$tsItem['node_order']);
    $tsuiteID = $ret['id'];
    $tsResult[] = array($tsItem['name'],$createSuc);

    }
    else
    {
    $tsuiteID = $info[0]['id'];
    $ret = $tsuiteMgr->update($tsuiteID,$tsItem['name'],"",null,$tsItem['node_order']);
    $tsResult[] = array($tsItem['name'],$updateSuc);
    }
    if(is_array($tsItem['children']) && count($tsItem['children'])>0){
    foreach($tsItem['children'] as $val){
    $tempTSArray[$val]['parentID'] = $tsuiteID;
    }
    }

    }
    // $end = microtime_float();
    // fwrite($hand, "每条规约用时:".($end-$begin)."\r\n");
    }
    }
    // echo "testsuiteArray前".memory_get_usage()."<br>";
    $testsuiteArray = null;
    // echo "testsuiteArray后".memory_get_usage()."<br>";
    $GLOBALS['testsuiteArray']=null;
    // echo "全局testsuiteArray后".memory_get_usage()."<br>";
    if(is_array($testcaseArray) && count($testcaseArray)>0){
    $tcData = array();
    // $begin = microtime_float();
    $flag = 0;
    foreach ($testcaseArray as $key=>$tsItem){
    if($tsItem['parentNum']==0){
    $parID = $parentID;
    }else{
    $parID = $tempTSArray[$key]['parentID'];
    }
    $tcData[$flag] = array(
    "name"=>$tsItem['name'],
    "node_order"=>$tsItem['order'],
    "parentID"=>$parID
    ) ;
    if(is_array($tsItem['property']) && count($tsItem['property'])>0){
    foreach($tsItem['property'] as $pKey=>$val){
    $tcData[$flag][$pKey] = $val;
    }
    }
    if(is_array($tsItem['custom_fields']) && count($tsItem['custom_fields'])>0){
    foreach($tsItem['custom_fields'] as $cfName=>$cfValue){
    $tcData[$flag][customfields][] = array("name"=>$cfName,"value"=>$cfValue);
    }
    }
    if(is_array($tsItem['srs']) && count($tsItem['srs'])>0){
    $tcData[$flag]['srs'] = $tsItem['srs'];
    }
    if(is_array($tsItem['produce']) && count($tsItem['produce'])>0){
    $tcData[$flag]['produce'] = $tsItem['produce'];
    }
    $flag++;
    }
    // $end = microtime_float();
    // fwrite($hand, "循环用例时间:".($end-$begin)."\r\n");
    // echo "testcaseArray前".memory_get_usage()."<br>";
    $testcaseArray = null;
    // echo "testcaseArray后".memory_get_usage()."<br>";
    $GLOBALS['testcaseArray']=null;
    // echo "全局testcaseArray后".memory_get_usage()."<br>";
    $tempTSArray = null;
    // echo "tempTSArray后".memory_get_usage()."<br>";
    if(is_array($tcData) && count($tcData)>0){
    // $begin = microtime_float();
    $resultMap = saveImportedTCData1($db,$tcData,$tproject_id,$userID,null,$duplicateLogic,$produceRelFB,$pfRe);
    $tcData = null;
    // echo "tcData后".memory_get_usage()."<br>";
    // $memory2 = memory_get_usage();
    // $end = microtime_float();
    // fwrite($hand, "保存用例总时间:".($end-$begin)."\r\n");
    // fwrite($hand, "总用时:".($end-$bTime)."\r\n");
    // fwrite($hand, "内存消耗:".($memory2-$memory1)."\r\n");
    }
    }


    $return = array("resultMap"=>$resultMap,"tsResult"=>$tsResult,"unexistPF"=>$unexistPF,"produceRel"=>$produceRelFB);
    return $return;
    // return $resultMap;

    }
    我说明下:$testsuiteArray和$testcaseArray是分析文件,得到的数组。两个数组可能有几十M或者上百M。
    现在问题不是想说数组太大,可以采用别的方法目的。问题出在我调用完这个函数,和这个函数里面的saveImportedTCData1函数,调用完saveImportedTCData1 内存也没有明显降低。我试过把所有返回结果跟那些引用的变量都销毁,内存还是占用很大,最终导致溢出了。这样看代码估计很累,谢谢了。
      

  4.   

    可以参考
    http://www.laruence.com/2011/03/04/1894.html
      

  5.   

    文件分析后,数组占用了20M
    然后数据库操作,这里涉及的操作很多。
    执行完后内存比最开始的大接近1G
    这样的结果是不是有什么异常啊。
    在处理过程中有把 没必要的数据都unset了。
      

  6.   

    5000个数组,每个数组里面还有的信息较多。
    执行了17W多的数据库操作,和40多秒的数据库执行时间
    采用循环操作。
    每执行完一个数组的操作内存逐渐增加。
    照理说每次循环用到得局部变量都一样。
    只有保存数据库操作结果的数组有增加,可是它的增加的量小。
    不可能需要那么大的内存。
    那这些额外的内存占用从哪里来呢?
    直到该函数调用完。这些内存空间都没释放,这是为什么呢?
    why?why?why?
    遇到这个瓶颈让我很苦恼。
      

  7.   

    经验丰富
    很有成就的大哥大叔们
    那多出来的内存怎么来的呢?
    HELP。。
      

  8.   

    版主大哥其他前辈思考过此问题的同学 一起讨论下- -
    我知道你很厉害
    之前就在百度找到你的信息
    过来帮帮忙吧。
    百度上能找到的信息我都找了
    php内存分配的原理什么的都看了
    有些资料也许没找着
    有没有解开疑问的
    从事php一年了 之前没有碰到这问题
    遇到问题 可以学得更多
    可是此时正在烦着呢 睡觉都会想这个问题
    有什么关于此类问题的书吗
    介绍下。。
    mygod
      

  9.   

    我以前碰到过的情况是create_function有内存泄漏,但你这里没有用这个大概只能自己慢慢调了,
    你装xdebug里面有几个功能可以帮助分析内存
      

  10.   

    你需要检查一下承载返回值的 $return 所占的空间
      

  11.   

    返回值 $return 被unset了
    还是占用很大$resultMap=saveImportedTCData1($db,$tcData,$tproject_id,$userID,null,$duplicateLogic,$produceRelFB,$pfRe);在这个函数调用前后的内存差别很大。
    我把返回结果$resultMap,$tcData,和$produceRelFB等有关联的数据都unset,还是一样。
    函数调用完不是释放完它执行时所分配的所有临时空间吗。怎么会这样子。想不通啊。那块内存哪去了?where are you- -
      

  12.   

    你去看下php的垃圾回收机制吧。
      

  13.   

    这个早在我是学生时代就了解java gc
    php gc也早就了解了跟java很像的机制。
    我现在是觉得不是这些问题
    我觉得应该深入php内核 研究下php内存分配机制
      

  14.   

    使用xdebug 只有执行实现 没有内存情况
    我用WinCacheGrind .exe 查看的
    还是我没找到- -
      

  15.   

    那就检查一下这个函数saveImportedTCData1,看看是不是因为他内部的问题
    另外如果是从数据库中获取数据,记录集资源有没有被释放……
      

  16.   

    谢谢楼上两位回答。
    自定义类 还有函数没错
    其实最大问题saveImportedTCData1 在这个函数。
    我把这个函数产生的所有输出都给释放掉了了。
    即使是释放完了 通过meomory_get_usage()输出的内存占用依然是调用这个函数之前内存调用的n倍
    大概多了一个数量级。
    我看我还是检查下这个函数
    话说xdebug 能通过WinCacheGrind  查看内存消耗吗
    我没看到有查看内存的 再次向回答人说谢谢
    ps:其实如果百度跟谷歌能找到我要的答案我一般不会问。我发现我问的问题大多数没有得到想要答案。能跟大家交流沟通也学习很多。再努力找原因。
      

  17.   

    自己排查吧,这个外人真帮不上什么忙,特别是你的saveImportedTCData1怎么写的都不知道。
    加下引用传递再测试一下,可能是因为你函数里有一次变量分离的,而变量本身又很大的缘故。
    $resultMap=saveImportedTCData1($db,&$tcData,$tproject_id,$userID,null,$duplicateLogic,&$produceRelFB,$pfRe);
      

  18.   

    恩 我的那个函数原型是刚好在$tcData,和$produceRelFB 有引用
      

  19.   

    刚才检查了一下
    上面那个函数中有行代码  $tcData[$flag][customfields][] = array("name"=>$cfName,"value"=>$cfValue);[customfields]忘了加引号,我记得曾经看手册有提到这个问题,这个会导致效率很低。
    因为php要额外很多检查。所以一直都是习惯加引号。可能不小心给忘了。
    结果因为大量数据 所以一下子开销差别就出来,我算了下空间开销差了二十倍。时间开销没算。
    问题还没解决还在找另一个函数出现的问题。
      

  20.   

    经过xdebug 再调试分析
    最终问题得以解决谢谢以上所有朋友