Php release memory in 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.

asked Aug 6, 2015 at 18:57

Php release memory in loop

12

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).

answered Aug 27, 2015 at 17:22

Php release memory in loop

1

I'm compiling my previous comments in an answer here. This doesn't explain exactly how you can free allocated memory, but it will guide you through a way to discover what in your application is causing that. With that, you can work on optimizing your code.

Finding memory usage bottlenecks is usually a challenging task. You can start by looking at your I/O-related calls, like database queries, file access, or even networking. Beyond increasing the execution time, sometimes these operations can allocate some amount of memory.

If you're already removing from memory the resources returned by I/O operations and no considerable decrease in allocated memory is noticed, the next step might be profiling your application using a tool like Blackfire (https://blackfire.io/).

Blackfire will give you a detailed view of each function call and its statistics on memory, CPU, and execution time. With that data, it's possible to check which operations are allocating excessive memory. You can find this info when you land your mouse pointer over the memory bar inside the call details, like this:

Php release memory in loop

answered Aug 12, 2015 at 16:03

Gustavo StraubeGustavo Straube

3,6496 gold badges35 silver badges60 bronze badges

1

It is very likely (provided with the information given) that there are still references to the created object which prevent the garbage collector from removing the object from memory. Since it is basically counting references, therefor making sure that no reference is being stored, by either making copies of values or unsetting them carefully this can be avoided.

Normally it is easier when using while(true) constructs to not create objects precisely for this reason and make it as self contained as possible just to make sure that no memory leaks can actually happen.

I know this answer is not very helpfull in a direct manner (and I do not have enough rep to comment on the question) but it might get you on the right track.

answered Aug 11, 2015 at 3:12

1

The problem is that you are in an infinite loop, with no end at the request. The garbage collector of PHP is designed to be dealt with at the end of the request, and it not accessible to the user otherwise. PHP is designed to be called and discarded, not to be kept alive indefinately. Hence it is not fixable. So, what I would suggest is to create a chron job that restarts the php loop at regular intervals thus ending the request and freeing up the memory. See this document for details.

answered Aug 17, 2015 at 16:56

KimvdLindeKimvdLinde

5678 silver badges19 bronze badges

My best guess (due to lack of knowledge of the internals of the Classes involved) is that either the classes assign other Objects as their properties (or perhaps they have self-references) or that the array used (since the code sample resembles the real case) has a reference to itself, which would explain the memory leak if the size of the array is significant.

If it is of any help, please check out the reference counting fundamentals from php.net:

http://php.net/manual/en/features.gc.refcounting-basics.php

answered Aug 14, 2015 at 9:14

m1lt0nm1lt0n

3613 silver badges9 bronze badges

As both @m1lt0n and @MartPluijmaekers has mention above, this might be an issue related to object references.

We don't know what is inside your Class() class and getSomeOtherObj() method, so I can't say anything for sure, however below snippet might be able to help you figure out if that is the case or not.

/* Here is your Class */
class Class {

    public function __construct () {
        $this->child = new AnotherClass( $this );
    }

    /* This is what you have to have ... */
    protected function __destruct () {
        unset( $this->child );
    }
}

/* Here is the other class  */
class AnotherClass {

    public function __construct ( $parent ) {
        $this->parent = $parent;
    }
}

/* Infinite Loop */
while ( true ) {

    $myObject = new Class();
    $myOtherObject = $myObject->getSomeOtherObj();

    $myArray = [1, 2, 3];

    /* manually destroying the object */
    $myObject->__destruct();
    unset( $myObject );

    /* rest of free-ing goes here ... */

    sleep(1); //Sleep at the end, to save CPU.
}

The snippet should be pretty much self-explanatory.

answered Aug 17, 2015 at 10:51

MahdiMahdi

9,0279 gold badges52 silver badges74 bronze badges

5

How to release variable memory in PHP?

An object or variable in PHP memory will be removed by the PHP garbage collector when there are no references to that object in the symbols table.

Does PHP unset clear memory?

unset() does just what its name says - unset a variable. It does not force immediate memory freeing. PHP's garbage collector will do it when it see fits - by intention as soon, as those CPU cycles aren't needed anyway, or as late as before the script would run out of memory, whatever occurs first.