1

I am getting "Fatal error: Allowed memory size of XXXX bytes exhausted...". I need to iterate through big amount of records, and execute a function to verify of the record fit the criteria which declare many class variables.

foreach ($results as $row)
{
  $location = Location::parseDatabaseRow($row);

  if ($location->contains($lat, $lon))
  {
    $found = true;
    $locations[] = $location;
    break;
  }
}

Implementation of the Location class:

public function contains($lat, $lon)
{ 
  $polygon =& new polygon();
  .... //Add points to polygons base on location polygons
  $vertex =& new vertex($lat, $lon);
  $isContain = $polygon->isInside($vertex); 

  $polygon->res(); //Reset all variable inside polygons
  $polygon = null; //Let Garbage Collector clear it whenever
  return ($isContain);
}

Shouldn't the $polygon be clear when contain() method is return? What can I do to reduce memory usage?

I am a Java developer, and started to learn PHP. Please help me understand on how to manage stack size and memory allocation and delocation. Thanks in advance.

Kirasaki
  • 23
  • 2
  • 1
    What does `$results` contain? Can you post the line where this variable gets defined and filled? Also which framework do you use? Laravel? The solution to this problem could be to only fetch one row at a time and then loop through it with `while()`, since it looks like you fetch all at once. – Charlotte Dunois Aug 08 '15 at 22:01
  • 1
    You can change memory limit in php.ini – Eugen Aug 08 '15 at 22:02
  • 1
    not sure what you are trying to do with the `=&`, but objects are by default pointers (almost) in php5 and up. If you really are beginning learning php, you may stick with normal allocation until you know what you are doing – Félix Adriyel Gagnon-Grenier Aug 08 '15 at 22:03
  • 1
    You could explicitly delete a variable by `unset` function: `unset $polygon`. http://php.net/manual/en/function.unset.php – Vlad DX Aug 08 '15 at 22:04
  • @CharlotteDunois $results are simply an arrays of string returned from a database query. – Kirasaki Aug 08 '15 at 22:05
  • 2
    @VladimirSerykh `unset()` does not really delete a variable, it just unsets the reference. Setting the variable to `NULL` would do the job of freeing memory. http://stackoverflow.com/questions/584960/whats-better-at-freeing-memory-with-php-unset-or-var-null – Charlotte Dunois Aug 08 '15 at 22:06
  • when a variable has no more references, it is cleared, isn't it though @CharlotteDunois? – Félix Adriyel Gagnon-Grenier Aug 08 '15 at 22:08
  • 1
    @FélixGagnon-Grenier Unsetting a variable doesn't necessarily immediately free the used memory. Setting a variable to `NULL` instead rewrite's the variable's data and may free memory if the variable used a lot memory. – Charlotte Dunois Aug 08 '15 at 22:09
  • @VladimirSerykh I also tried to unset($polygon), but it doesn't seem to do it. – Kirasaki Aug 08 '15 at 22:12
  • In this case though, I think it would be freed at the end of the scope. Which is the line after setting it to null. – Félix Adriyel Gagnon-Grenier Aug 08 '15 at 22:12
  • @Kirasaki Well, telling me what it does doesn't really help. Post the specific php code line(s). Can you also please post the full error message and tell us which line it is in your minimal posted code? – Charlotte Dunois Aug 08 '15 at 22:15
  • @FélixGagnon-Grenier Unfortunately PHP's Memory Management isn't the best, which is why it doesn't immediately lead to memory freeing if you simply unset a variable. What you need to do is rewriting the variable's data to `NULL`, which leads to immediately memory freeing. – Charlotte Dunois Aug 08 '15 at 22:16
  • Yes, I know, what I'm saying is variables in this case are local to a scope. Once the scope is left, the variable will be freed. Setting it to null just before the scope is left has no effect. – Félix Adriyel Gagnon-Grenier Aug 08 '15 at 22:18
  • Thanks for trying to help. The [polygon](http://s000.tinyupload.com/?file_id=00733064261685885040) and [vertex](http://s000.tinyupload.com/?file_id=04297066103442847261) are open source I found to trying to detect a point is within a polygon. The only methods I'm using from `polygon` is `addv` and `isInside`. Complete PHP memory error _Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 42 bytes) in /home/content/72/8478372/html/gpscheckin/polygon.php on line 392_ – Kirasaki Aug 08 '15 at 22:28

1 Answers1

1

I am a Java developer, and started to learn PHP.

Here are some corrections which may allow your code to not exhaust memory limit.

use a while. Since your result comes from a database query, you should have the possibility to use fetch() instead of fetchAll() which I assume you are using since you are applying a foreach() on it.

while ($row = $result->fetch()) { // here $result is supposed to be a PDOStatatement.
    $location = Location::parseDatabaseRow($row);
    if ($location->contains($lat, $lon)) {
        $found = true; // where is this used?
        $locations[] = $location;
        break;
    }
}

While uses less memory because not all results are fetched at the same time.

use the ampersand the right way. You are doing a new in each loop. The ampersand is used when you want to pass a value by reference to a function, so that it is affected outside that function scope without the need to return it.

Here, you are using objects, which are somewhat passed by reference by design.

public function contains($lat, $lon) {
    $polygon = new polygon();
    $vertex = new vertex($lat, $lon);
    return $polygon->isInside($vertex);
    // no need to reset the values of your polygon, you will be creating a new one on the next loop.
}

for completeness sake here a version using the same polygon object. Notice how I do not use an ampersand because we are passing an object.

$polygon = new polygon();
while ($row = $result->fetch()) { // here $result is supposed to be a PDOStatatement.
    $location = Location::parseDatabaseRow($row);
    if ($location->contains($lat, $lon, $polygon)) {
        $found = true; // where is this used?
        $locations[] = $location;
        break;
    }
}

public function contains($lat, $lon, $polygon) {
    //Add points to the passed polygon
    $vertex = new vertex($lat, $lon);
    $isContain = $polygon->isInside($vertex);
    $polygon->res(); 
    // since we eill be using the same $polygon, now we need to reset it
    return $isContain;
}
  • 1
    That works. Instantiating polygon once, and reuse it seem to fix it. Also instead of fetchAll(), using `while ($row = $result->fetch())` helps by not loading all database results into memory. Thanks for the help. – Kirasaki Aug 09 '15 at 20:07