How to free memory in PHP? - php

public function foo($file1, $file2){
$obj = new Obj();
$data = array();
$data[] = $obj->importAFile($file1);
$data[] = $obj->importAFile($file2);
return $data;
}
Does the memory allocated for $obj get freed after the return?
If not how can I free it?

By using unset() on a variable, you've marked it for 'garbage collection' literally, as PHP doesn't really have one, so the memory isn't immediately available. The variable no longer houses the data, but the stack remains at the current size even after calling unset(). Setting the variable to NULL drops the data and shrinks the stack memory almost immediately.
This has worked for me on several occasions where memory exhausted warnings were thrown before the tuning, then calling unset() after nullifying the variable. Calling unset after nullifying mightn't be necessary but I used it nonetheless after the nullification.

PHP uses garbace collector. It frees all variables to which there are no references left. Assuming that $obj->importAFile() does not return reference to $obj, the memory will be freed. However, there is no guarantee when the memory will be freed. If $obj contains reference to itself, in older versions of PHP the memory won't be freed as well. You can read more in PHP documentation

It manages memory for you. You might have a problem only when there are some circular references between your objects

Related

Assigning NULL to a PHP variable doesn't clean the memory

I have read several times that, in order to invoke the garbage collector and actually clean the RAM used by a variable, you have to assign a new value (e.g. NULL) instead of simply unset() it.
This code, however, shows that the memory allocated for the array $a is not cleaned after the NULL assignment.
function build_array()
{
for ($i=0;$i<10000;$i++){
$a[$i]=$i;
}
$i=null;
return $a;
}
echo '<p>'.memory_get_usage(true);
$a = build_array();
echo '<p>'.memory_get_usage(true);
$a = null;
echo '<p>'.memory_get_usage(true);
The output I get is:
262144
1835008
786432
So part of the memory is cleaned, but not all the memory. How can I completely clean the RAM?
You have no way to definitely clear a variable from the memory with PHP.
Its is up to PHP garbage collector to do that when it sees that it should.
Fortunately, PHP garbage collector may not be perfect but it is one of the best features of PHP. If you do things as per the PHP documentation there's no reasons to have problems.
If you have a realistic scenario where it may be a problem, post the scenario here or report it to PHP core team.
Other unset() is the best way to clear vars.
Point is that memory_get_usage(true) shows the memory allocated to your PHP process, not the amount actually in use. System could free unused part once it is required somewhere.
More details on memory_get_usage could be found there
If you run that with memory_get_usage(false), you will see that array was actually gc'd. example

Dump all variables in PHP

There's a memory leak in my script and I couldn't find it after 2 days. I found the loop that is causing the memory leak; each iteration of the loop increases the memory usage. I moved the loop into a function to isolate the variables. At the end of the function, I unsetted every variable created by the function so that get_defined_vars() returns an empty array. Here's what I mean:
function the_loop(){
$var="value";
... // processing, including using a library
unset($var);
print_r(get_defined_vars()); // prints empty array
}
while(true){
the_loop();
echo memory_get_usage()."\n"; // steadily increases until memory limit is reached
}
I'm guessing that some variables defined in the_loop() are still in memory. I tried using XDebug's trace tool, but it didn't help. All it showed was that memory usage increases on average over the long run. I'm looking for a tool that can show me all the values in PHP's memory. I will be able to recognize the variable based on the value. What tool can dump PHP's memory?
As Dragon mentioned unset doesn't instantly free memory.
What's better at freeing memory with PHP: unset() or $var = null
I'd consider re-evaluating the way you're using PHP, it's not designed for long/constant running scripts, the garbage handler simply isn't that great.
If you want to dig further into the executing script I'd suggest checking out some tools like:
https://github.com/jokkedk/webgrind
http://xhprof.io/
http://derickrethans.nl/xdebug-and-tracing-memory-usage.html
Also worth a read: What gc_collect_cycles function is useful for?
Calling unset() does not force garbage collection, so while the reference count should decrease there may be others referencing it. Use xdebug_debug_zval($var) before calling unset to see how many references to its value there actually are.

Memory leak in Magento/Zend Framework

When running this simple script I get the output posted below.
It makes me think that there is a memory leak in either my code or the Zend Framework/Magento stack. This issue occurs when iterating any kind of Magento collection.
Is there anything that I am missing or doing wrong?
Script:
$customersCollection = Mage::getModel('customer/customer')->getCollection();
foreach($customersCollection as $customer) {
$customer->load();
$customer = null;
echo memory_get_usage(). "\n";
}
Output:
102389104
102392920
...
110542528
110544744
Your issue is that you are issuing fairly expensive queries with each iteration, when you could load the necessary data via the collection queries:
$collection = Mage::getResourceModel('customer/customer_collection')->addAttributeToSelect('*');
will do the same, but all in one query. The caveat to this approach is that if there are any custom event observers for customer_load_before or customer_load_after events (there are no core observers for these), the observer will need to be run manually for each data model.
Edit: credit to osonodoar for spotting an incorrect class reference (customer/customer vs customer/customer_collection)
The memory for an object (or other value) can only be freed when there are no references to it anywhere in the PHP process. In your case, the line $customer = null only decreases the number of references to that object by one, but it doesn't make it reach zero.
If you consider a simpler loop, this may become clearer:
$test = array('a' => 'hello');
foreach ( $test as $key => $value )
{
// $value points at the same memory location as $test['a']
// internally, that "zval" has a "refcount" of 2
$value = null;
// $value now points to a new memory location, but $test['a'] is unnaffected
// the refcount drops to 1, but no memory is freed
}
Because you are using objects, there is an added twist - you can modify the object inside the loop without creating a new copy of it:
$test = array('a' => new __stdClass);
// $test['a'] is an empty object
foreach ( $test as $key => $value )
{
// $value points at the same object as $test['a']
// internally, that object has a "refcount" of 2
$value->foo = "Some data that wasn't there before";
// $value is still the same object as $test['a'], but that object now has extra data
// This requires additional memory to store that object
$value = null;
// $value now points to a new memory location, but $test['a'] is unnaffected
// the refcount drops to 1, but no memory is freed
}
// $test['a']->foo now contains the string assigned in the loop, consuming extra memory
In your case, the ->load() method is presumably expanding the amount of data in each of the members of $customersCollection in turn, requiring more memory for each. Inspecting $customersCollection before and after the loop would probably confirm this.
First off, when unsetting variables use unset($variable) instead of $variable=null. It does essentially the same thing, but is much clearer as to your intent.
Second, PHP is meant to die - memory leaks aren't a huge issue, as a PHP request lasts maybe a few seconds, and then the process dies and all memory it was using is freed up for the next request. Unless you are running into scaling issues, it's nothing to worry about.
Edit: which isn't to say don't worry about the quality of your code, but for something like this, its most likely not worth the effort of trying to prevent it from happening unless it is causing problems.
Other way out to handle memory leak is that call exec within loop and let that exec function do the job part which results in memory leak.
So once it completes its part and terminates all memory leak within that exec will be released.
So with huge iterations this memory loss which keeps adding otherwise will be taken care.
#benmarks response would be the right approach here, as calling load() within a loop is a very very expensive call.
Calling $customer->load() would allocate memory incrementally that would be referenced by $customersCollection, that memory won't be released until the end of the loop.
However, if load() needs to be called for any reason, the code below won't leak memory, as the GC releases all the memory allocated by the model in each iteration.
$customersCollection = Mage::getModel('customer/customer')->getCollection();
foreach($customersCollection as $customer) {
$customerCopy = Mage::getModel('customer/customer')->load($customer->getId());
//Call to $customerCopy methods
echo memory_get_usage(). "\n";
}

PHP function variables and the garbage collector

I was wondering if anyone could answer me this quick question. I tried searching it but I get similar questions but in the wrong context.
What I am wondering is take this code:
function foo()
{
$test_array = array();
for($i=0; $i<10000000; $i++)
{
$test_array[] = $i;
}
}
What happens to $test_array after the function finishes. I know that it looses scope, I am not new to programming.
What I am wondering is should I call
unset($test_array);
before the function ends or does PHP set it for deletion to the garbage collector as the function ends?
I used the for loop just to show a variable of a fair size to get my point across.
Thanks for reading
Kevin
Once $test_array is no longer in scope (and there are no additional references that point to it), it is flagged for garbage collection.
It ceases to be in scope when the process returns from the function to the calling routine.
So there is no need to unset it.
This would only be different if you had declared $test_array as static.
unset() doesn't free the memory a variable uses, it just marks it for the garbage collector which will decide when to free the memory (when it has free cpu cycles or when it runs out of memory, whichever comes first).
However you have to realize that ALL memory used by a PHP script is freed when the script finishes which, most of the time, is measured in milliseconds, so if you're not doing any lengthy operations that would exceed the "normal" execution time of a PHP script you shouldn't worry about freeing memory.

What is the best method for memory cleanup in PHP? (5.2)

I have two simple questions. What is better/useful for memory cleanup.
$var = null;
or
unset($var);
I have one function with one cycle. I am getting (after few minutes)
Fatal error: Allowed memory size of 419430400 bytes exhausted
I am setting null and unset()-ing every object (at the end of the cycle) but still without any success :( I cant find out what is consuming memory.
And what about function calls in cycle? Will PHP release all allocations in these functions?(after call)
PHP itself confuses both concepts sometimes but, in general, a variable set to NULL is not the same as a variable that does not exist:
<?php
$foo = 'One';
$bar = 'Two';
$foo = NULL;
unset($bar);
var_dump($foo); // NULL
var_dump($bar); // Notice: Undefined variable: bar
var_dump(get_defined_vars()); // Only foo shows up: ["foo"]=> NULL
?>
unset() does just that, it unsets a variable; but it does not immediate free up memory.
PHP's garbage collector will actually free up memory previously used by variables that are now unset, but only when it runs. This could be sooner, when CPU cycles aren't actively being used for other work, or before the script would otherwise run out of memory... whichever situation occurs first.
And be aware that unset won't necessarily release the memory used by a variable if you have other references to that variable. It will simply delete the reference, and reduce the reference count for the actual stored data by 1.
EDIT
While unset doesn't immediately release the memory used (only garbage collection actually does that) the memory that is no longer used as a result is available for the declaration of new variables
I found problem.
First it was caused by xdebug profilling tools (i have turned on everything :) ) - and it consume lot of memory.
So remember: xdebug (when profilling turned on) consumes some memory in PHP process of your application
Second, I didn't release static members used in called functions.
If you unset the variable it is just marked, so on the next garbage collection it will be removed. If setting to null, the data of the variable gets overwritten.
Maybe see also the comments on the php manual: Unset Manual
At least this behaviour is also what i have encountered so far.
But to fix it, you should first try to find out what is causing the memory to grow. The memory_get_usage function should be helpful for this.
And what about function calls in cycle? Will PHP release all allocations in these functions?(after call)
Once the execution leaves the scope of a function, all non-static variables are removed from memory.

Categories