Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory usage increasing after every loop

I have a foreach loop, reading a file containing about 200000 lines, this is my PHP :

foreach ($this->file as $row)
      {
        if ($this->file->valid())
        {

          //init client array
          $this->initInvoicesArray($row);
          $this->prepareInvoice();
          $row = null;
          $this->key = $this->file->key();

          //add msisdn to msisdn array, and client to clients array
          self::$MsisdnArray[] = $this->msisdn;
          self::$InvoicesArray[$this->msisdn] = $this->client;

          if ($i % 3000 == 0) 
          {
            //get valid users from table
            $this->prepareAndSaveValidClients();
          }

          $i++;
        }
      }

and this is the prepareAndSaveValidClients() function :

public function prepareAndSaveValidClients(){
    $query = Doctrine_Query::create()
        ->select('p.gender, p.email2, u.username, u.first_name, u.last_name, u.email_address, u.is_active, p.msisdn, p.user_id, p.city_id, p.street, p.zipcode, p.msisdn_status')
        ->from('sfGuardUser u')
        ->innerJoin('u.Profile as p ON u.id = p.user_id')
        ->whereIn('p.msisdn', self::$MsisdnArray)
        ->whereIn('p.status', self::$AllowedStatus);

    $results = $query->fetchArray();

    //instanciat an object collection for payment_notifications
    $collection = new Doctrine_Collection("payment_notifications");

    if (!empty($results))
    {
      foreach ($results as $key => $client)
      {
        $invoice = self::$InvoicesArray[$client['Profile']['msisdn']];

        $this->initInvoicesArray($invoice);
        $this->prepareInvoice();

        $this->prepareUserProfile($client);
        $this->prepareClient();

        $paymentNotifications = new paymentNotifications();
        $paymentNotifications->fromArray($this->client);

        $collection->add($paymentNotifications);

        $tel = $client['Profile']['msisdn'];
        $client = null;
      }

      $collection->save();

      //clear memory
      $results = null;
      $collection = null;
      self::$MsisdnArray = null;
      self::$InvoicesArray = null;


      $this->logSection('tel num', 'added :' . $tel . ' Memory usage : ' . memory_get_usage());
      $duration = microtime(true) - $this->startTime;
      $this->logSection('payment : ', sprintf('added in %s', $duration));
    }
  }

As for the functions :

   $this->initInvoicesArray($invoice);
   $this->prepareInvoice();

   $this->prepareUserProfile($client);
   $this->prepareClient();

They are just for preparing $this->client

This is Memory Usage as it's displayed for every loop :

>> tel num   added :0699946185 Memory usage : 89287596
>> payment :  added in 8.6373870372772
>> tel num   added :0699983919 Memory usage : 165854544
>> payment :  added in 18.373502969742
>> tel num   added :0699949623 Memory usage : 241338788
>> payment :  added in 29.336947917938
>> tel num   added :0699854750 Memory usage : 319173092
>> payment :  added in 40.880628824234

As you can see, I tried to free memory of these variables :

$results = null;
$collection = null;
self::$MsisdnArray = null;
self::$InvoicesArray = null;

But in vain, Memory Usage keeps increasing after every loop, which results in a An Allowed Memory size exausted fatal error. How can I optimize it?

Thank you.

like image 920
SmootQ Avatar asked Apr 14 '15 08:04

SmootQ


People also ask

Why does my RAM usage keeps increasing?

This sounds like a memory leak. Make sure to update all your drivers and uninstall any programs that you do not use.

Does while loop consume memory?

After iterating 30-60 000 times when running the AskScript program (below) node process consumed up to 2GB of RAM.

What happens if you write an infinite loop and the computer runs out of memory?

Even if your loop is infinite, it will keep running and once it runs out of memory, it will crash and automatically get terminated.


2 Answers

Doctrine objects have circular references that php has trouble to free. To solve this, doctrine provides free() method, call it on the collection just before setting it to null:

$collection->free(true);
$collection = null;
like image 75
Marek Avatar answered Oct 14 '22 12:10

Marek


After calling $this->prepareAndSaveValidClients(); you could also use the gc_collect_cycles() function. It will help with possible memory leaks.

like image 39
lsouza Avatar answered Oct 14 '22 10:10

lsouza