Search code examples
phpmemorygarbage-collection

How do I resolve memory issues inside a loop


I have a snippet that resembles the following:

while (true) {
    $myObject = new Class();
    $myOtherObject = $myObject->getSomeOtherObj();
    ...
    $myArray = [1, 2, 3];
    ...
    sleep(1); //Sleep at the end, to save CPU.
}

This snippet should run as a daemon service, but I'm having a lot of trouble making this work.

The issue: each iteration increases the process memory usage. As if at each new iteration a new $myObject is being instantiated, but the previous one remains allocated in memory, and such.

I have tried:

  • to unset all variables at the end of the loop (right before the sleep()).
  • Setting all variables to null.
  • encapsulating them in a separate function (while (true) { doThis(); })
  • manually calling gc_collect_cycles()

None of those worked to decrease memory usage.

I have no idea how to force all memory to be released.


Solution

  • After much research on the topic, I am finally convinced that there are no ways to manually force the memory to be released or to force object destruction.

    However, something that has helped me lower the memory usage (absolutely preventing infinite memory stacking was not possible) was to realize that there are no loop scopes in PHP and that the Garbage Collection happens when switching scopes.

    In C# or Java, a variable created within a while (...) {} is only accessible from within the loop. This is not the norm for PHP. A $myObject created from within a while instruction is accessible throughout your entire application.

    This means the provided snippet would be better presented as:

    while (true) {
        myFunc();
    }
    
    function myFunc()
    {
        $myObject = new Class();
        $myOtherObject = $myObject->getSomeOtherObj();
        ...
        $myArray = [1, 2, 3];
        ...
        sleep(1); //Sleep at the end, to save CPU.
    }
    

    Encapsulating the logic in a function forces the scope to change, which means the Garbage Collector will be called at each iteration. This has not solved my problem, but it has lowered my RAM usage somewhat.

    What I have learned from this experience is that PHP is probably not suited to this specific project requirement. I'd need more control over memory, and PHP doesn't provide any kind of control over created/destroyed objects. Some native functions do not release memory properly (specially those that do I/O, database access and memcached).