Php 为什么我的应用程序内存不足?使用chunk取消设置变量

Php 为什么我的应用程序内存不足?使用chunk取消设置变量,php,laravel,laravel-4,eloquent,Php,Laravel,Laravel 4,Eloquent,我有下面这个简单的应用程序。我正在关闭Laravel中的查询日志记录,在可能的情况下,我不确定,但是在2GB Linode内存不足之前,这个函数将只处理大约800条记录。我知道我问了你们很多问题,但我看不出我在哪里泄露了记忆 实际上只有两个主要步骤 步骤1-将记录从临时表移动到生产中 class ListingMigrator { public function __construct($tempListing, $feed) { $this->tempLi

我有下面这个简单的应用程序。我正在关闭Laravel中的查询日志记录,在可能的情况下,我不确定,但是在2GB Linode内存不足之前,这个函数将只处理大约800条记录。我知道我问了你们很多问题,但我看不出我在哪里泄露了记忆

实际上只有两个主要步骤

步骤1-将记录从临时表移动到生产中

class ListingMigrator
{
    public function __construct($tempListing, $feed)
    {
        $this->tempListing = $tempListing;
        $this->listing = $this->listingInstance();
        $this->feed = $feed;
    }

    public static function migrateListing($listing, $feed)
    {
        $instance = new static($listing, $feed);
        return $instance->migrate();
    }

    public function migrate()
    {
        $this->addExternalData();
        $this->populateListing();
        $this->processPhotos();
        $this->deleteTempListing();
    }

    private function listingInstance()
    {
        DB::connection()->disableQueryLog();
        $listing = Listing::findByMud($this->tempListing->matrix_unique_id);
        return $listing ?: new Listing;
    }

    private function processPhotos()
    {
        $retsApi = new RetsFeedApi($this->feed);
        /* Initialize Object */
        $rets = $retsApi->findMostRecent();
        $photos = $rets->getPhotosForListing($this->listing->matrix_unique_id);
                        foreach ($photos as $photo)
                        {
                            $uploader = new PhotoProcessor($this->listing, $photo);
                            $uploader->process();
                        }
    }

    private function populateListing()
    {
        DB::connection()->disableQueryLog();
        $this->listing->fill($this->tempListing->toArray());
        $this->listing->imported_at = $this->tempListing->created_at;
        $this->listing->board = $this->tempListing->board;

        return $this->listing->save();
    }

    private function addExternalData()
    {
        // Get Google lattitude and longitude
        $googlecoords = getGoogleMapInfo($this->tempListing->FullAddress, $this->tempListing->City);
        $this->listing->GoogleLat = $googlecoords['GoogleLat'];
        $this->listing->GoogleLong = $googlecoords['GoogleLong'];

        // Add or update the Subdivision Table (helper function)
        $subdivisiondata = SubdivisionUpdate($this->tempListing->board, $this->tempListing->SubCondoName, $this->tempListing->Development);
        $this->listing->SubdivisionID = $subdivisiondata['id'];
    }

    private function deleteTempListing()
    {
        return $this->tempListing->delete();
    }
}
第2步-下载照片并重新上传到Amazon S3

class PhotoProcessor
{
  public function __construct(Listing $listing, $photoData)
  {
    $this->bucket       = 'real-estate-listings';
    $this->s3           = App::make('aws')->get('s3');
    $this->tempFileName = 'app/storage/processing/images/retsphotoupload';
    $this->photoData    = $photoData;
    $this->listing      = $listing;
    $this->photo        = new RetsPhoto;
  }

  public function process()
  {
    $this->storeTempFile();
    $this->storeFileInfo();
    $this->buildPhoto();

    $success = $this->pushToS3();

    // if Result has the full URL or you want to build it, add it to $this->photo
    DB::connection()->disableQueryLog();
    $this->listing->photos()->save($this->photo);  
    $this->removeTempFile();
    unset ($this->photoData);
    return $success;
  }

  private function storeTempFile()
  {
    return File::put($this->tempFileName, $this->photoData['Data']) > 0;
  }

  private function storeFileInfo()
  {
    $fileInfo = getimagesize($this->tempFileName);
    // Could even be its own object
    $this->fileInfo = [
    'width'     => $fileInfo[0],
    'height'    => $fileInfo[1],
    'mimetype'  => $fileInfo['mime'],
    'extension' => $this->getFileExtension($fileInfo['mime'])
    ];
  }

  private function buildPhoto()
  {
    $this->photo->number = $this->photoData['Object-ID']; // Storing this because it is relevant order wise
    $this->photo->width  = $this->fileInfo['width'];
    $this->photo->height = $this->fileInfo['height'];
    $this->photo->path   = $this->getFilePath();
  }

  private function getFilePath()
  {
    $path   = [];
    if ($this->listing->City == NULL)
    {
      $path[] = Str::slug('No City');
    }
    else
    {
      $path[] = Str::slug($this->listing->City, $separator = '-'); 
    }

    if ($this->listing->Development == NULL)
    {
      $path[] = Str::slug('No Development');
    }
    else
    {
      $path[] = Str::slug($this->listing->Development, $separator = '-');  
    }

    if ($this->listing->Subdivision == NULL)
    {
      $pathp[] = Str::slug('No Subdivision');
    }
    else
    {
      $path[] = Str::slug($this->listing->Subdivision, $separator = '-');  
    }

    if ($this->listing->MLSNumber == NULL)
    {
      $pathp[] = Str::slug('No MLSNumber');
    }
    else
    {
      $path[] = Str::slug($this->listing->MLSNumber, $separator = '-');
    }

      $path[] = $this->photoData['Object-ID'].'.'.$this->fileInfo['extension'];

      return strtolower(join('/', $path));
  }

  private function pushToS3()
  {
    return $this->s3->putObject([
      'Bucket'     => $this->bucket,
      'Key'        => $this->photo->path,
      'ContentType'=> $this->fileInfo['mimetype'],
      'SourceFile' => $this->tempFileName
    ]);
  }

  private function getFileExtension($mime)
  {
    // Use better algorithm than this
    $ext = str_replace('image/', '', $mime);
    return $ext == 'jpeg' ? 'jpg' : $ext;
  }

  private function removeTempFile()
  {
    return File::delete($this->tempFileName);
  }
}
编辑以显示RetsPhoto

class RetsPhoto extends Eloquent {

    protected $table = 'rets_property_photos';

    public function listing() {

        return $this->belongsTo('Listing', 'matrix_unique_id', 'matrix_unique_id');
    }

}
编辑#2:区块调用 这在app/命令中,其中唯一的一个功能是下面的fire()函数:

public function fire()
{
    // Turn off query logging
    DB::connection()->disableQueryLog();

    $feeds = RetsFeed::where('active','=',1)->get();
    foreach ($feeds as $feed)
    {

        $class = "TempListing{$feed->board}";

        $listings = $class::orderBy('MatrixModifiedDT','desc');

        $listings->chunk(50, function($listings) use($feed) {
            $listings->each(function($listing) use ($feed) {
                ListingMigrator::migrateListing($listing,$feed);
                echo "Feed: $feed->board\r\n";
                echo "SubcondoName: $listing->SubCondoName\r\n";
                echo "Development: $listing->Development\r\n";
                echo "\r\n";
            });
        });
    }

}

我想我已经弄明白了

  • 您的系统在内存中保存所有照片数据。由unset见证($this->photoData)

  • 问题是您需要首先完成流程功能。您的应用程序不太可能处理任何照片,因此当您继续从文件系统抓取照片时,甚至在处理一张照片之前,您的内存就用完了
  • 要确认这一点,只需抓取一个不使用chunk方法的文件。 我不太熟悉拉威尔,它可能会同时抓取所有文件并吃掉公羊


    您可以使用memory\u get\u usage(true)进行一些跟踪,以查明ram的确切位置。我建议先分析fire方法。

    我感觉
    getimagesize
    会将资源加载到内存中。@Marty我该怎么说呢?我现在正在努力确定,以及如何释放内存。你可以尝试使用
    imagecreatefromjpeg
    并从中获取图像大小,然后在上面使用
    imagedestroy
    ,看看这是否有区别。这与我有关$此->照片=新的RetsPhoto;请用那个类更新帖子。我不知道。它将临时表中的一条记录的所有照片拉入,并将该记录迁移到主表,下载图像并将其重新加载到S3,然后继续。它一次下载一张图片。