Php free memory after function

PHP has garbage collector which takes care of the memory management for you, which affects to memory usage (of the process) in several different ways.

First, when inspecting memory usage of a process outside of the process, even if PHP sees some memory to be freed, it may not be released back to the OS for optimization purposes related to memory allocation. This is reduce overhead from continuous frees and allocs, that happen more easily with GC’d languages, as allocation procedure is not visible to the actual program.

For that reason, even if one calls gc_collect_cycles() by hand, the memory may not be freed to the OS at all, but rather reused for future allocations. This causes PHP to see smaller memory usage than the process in reality uses, due to some early big reservation which never gets to freed back to the OS.

Second, due to nature of garbage collection, the memory may not be immediately freed after marked unused by the program. Calling gc_collect_cycles() will make the memory freed immediately, but it should be seen unnecessary, and does not work if you have logical (or something in PHP leaks) memory leak in your script.

For knowing what is going on, doing line by line inspection (for example with Xdebug’s function trace) would give you better insight about how PHP (or rather, your program) sees the memory usage.

Combining that to line-by-line inspection from outside of the process (for example your pmap commands) would tell if the PHP actually is freeing any memory at any point after reserving it.

The behaviour of PHP’s Garbage Collection (GC) can be a small mystery and you might wonder how it works and if you can optimize its usage for your application.

Is your script running out of memory and you are looking for ways to reduce it? PHP’s GC is a way to to reduce the memory of your script. However, arbitrarily littering your code with gc_enable(), gc_disable() and gc_collect_cycles() calls everywhere does not automatically help and obviously reduces the expressiveness of your code.

Do you know if the garbage collector is slowing down your requests or speeding them up? When does it get triggered automatically? How much memory does each run clean up?

Maybe you fear that your application is suffering from a similar inefficient garbage collection usage than Composer did three years ago, where selectively disabling the collector improved their performance by up to 90%.

Sadly, answers to these questions are not available to you from the PHP engine, unless you want to recompile with obscure debug flags. Yeah, no thank you!

Before I show you a tool to access all the necessary information, you should first understand the available optimization potential and trade-offs with PHPs GC. Because sometimes you need to enable the garbage collector and sometimes its better to disable it.

The following summary is as bare bones as it can get to understand PHP memory. Please see Anthony Ferrara’s post on “What about garbage” if you want to dive deep into this topic.

How does PHP cleanup memory?

  1. If a variable falls out of scope and is not used in any other place of the currently executed code anymore, then it is garbage collected automatically. You can force this early by using unset() to end variables scope early.

  2. If a variable is part of a cyclic reference, where A points to B and B back to A, then the variable can only be cleaned up by PHPs cycle garbage collector. It is triggered whenever 10000 possible cyclic objects or arrays are currently in memory and one of them falls out of scope. The collector is enabled by default in every request, but it can be toggled with the functions gc_enable() and gc_disable().

  3. If you call the function gc_collect_cycles(), then collection of cyclic references is triggered explicitly even if you don’t have 10000 of them in memory yet.

The optimal performance strategy is to enable the garbage collector when the GC can clean up as many possible (high efficiency, many cleanups) from the potential 10000 cyclic references and to disable it when it finds out that most of them are still used (low efficiency, few cleanups).

But how then can you find out if you need to enable or disable the garbage collection or not? As I mentioned PHP does not actually provide statistics about cleanup mechanisms 2 and 3.

The garbage_stats PHP extension

This is where our small PHP extension garbage_stats comes to the rescue. It is based on the garbage collection hook that I co-proposed with Adam Harvey for PHP 7 and up. Most of the code is extracted from our tideways extension and enhanced by a simple CLI mode to print statistics without requiring changes to your code.

Lets run garbage_stats with a version of Composer that does not disable garbage collection to simulate the previous bottleneck:

$ php -dgc_stats.enable=1 -dgc_stats.show_report=1 bin/composer update Found 157 garbage collection runs in current script.

Collected | Efficency% | Duration | Reduction% | Function ----------|------------|----------|------------|---------       796 |     7.96 % |  2.59 ms |     0.63 % | [..]::loadProviderListings         0 |     0.00 % |  0.91 ms |    -0.00 % | [..]::loadProviderListings         0 |     0.00 % | 17.19 ms |    -0.01 % | [..]::parseConstraints         0 |     0.00 % | 19.95 ms |    -0.03 % | ArrayLoader::load         0 |     0.00 % | 22.36 ms |    -0.02 % | Pool::computeWhatProvides         0 |     0.00 % | 30.40 ms |    -0.01 % | ArrayLoader::parseLinks         0 |     0.00 % | 29.05 ms |    -0.00 % | Rule2Literals::equals         0 |     0.00 % | 29.00 ms |    -0.01 % | [..]::createRule2Literals         0 |     0.00 % | 32.90 ms |    -0.09 % | RuleWatchNode::__construct         0 |     0.00 % | 35.08 ms |    -0.09 % | Solver::solve         0 |     0.00 % | 44.10 ms |    -0.09 % | makeAssertionRuleDecisions         0 |     0.00 % | 53.28 ms |    -0.01 % | Solver::runSat         0 |     0.00 % | 24.21 ms |    -0.00 % | Transaction::findUpdates       183 |     1.83 % | 31.34 ms |     0.01 % | Installer::doInstall         0 |     0.00 % | 24.10 ms |    -0.00 % | Installer::doInstall 

IEKS. The table only shows a selection of the 157 garbage collection runs, but except two of them they all collect 0 cyclic references when running and don’t reduce the memory at all while still running for 10ms and more. ICEBERG AHEAD! This is the use-case for calling gc_disable() during the whole execution of your long running script.

Contrast this with a simple test script that can efficiently clean up cyclic references with the this output:

Found 7 garbage collection runs in current script.

Collected | Efficency% | Duration | Reduction% | Function ----------|------------|----------|------------|---------         0 |     0.00 % |  0.00 ms |    -0.14 % | gc_collect_cycles     10000 |   100.00 % |  4.23 ms |    89.43 % | foo     10000 |   100.00 % |  3.32 ms |    89.40 % | foo     10000 |   100.00 % |  2.48 ms |    89.37 % | foo     10000 |   100.00 % |  5.01 ms |    89.33 % | Test::foo      9000 |    90.00 % |  2.50 ms |    79.74 % | Test::foo     10000 |   100.00 % |  3.15 ms |    81.36 % | Test::foo 

But what if your long running script does not fall into the fully efficient (~100%) or inefficient (~0%) section? The solution is simple and requires thorough work:

  1. With the garbage_stats extension, find out which section of your code is triggering the garbage collection inefficiently. In web requests you can use the function gc_stats() to get information about individual garbage collection runs.
  2. Call gc_disable() before a non GC-efficient code section is executed.
  3. Call gc_enable() after a non GC-efficient code section is finished and then gc_collect_cycles() to clean up.

Happy efficient garbage collection!

P.S.: Tideways is collecting garbage collection details across your application in production If you want to find out how garbage collection affects your user performance, sign up for a 30 days trial.

How to clear PHP memory?

If you want to clear the memory then you can use unset or just put into another function then the variables will be cleared. Memory and performance go hand in hand, so it is useful to implement caching in your PHP application. You should not run same processes multiple times if possible.

What's better at freeing memory with PHP unset () or $var Null?

null variable: It speedily frees the memory.

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.

How PHP garbage collector works?

The garbage collector is triggered whenever 10,000 possible cyclic objects or arrays are currently in memory, and one of them falls out of scope. The collector is enabled by default in every request. And this is, generally a good thing.