Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force freeing memory in PHP

In a PHP program, I sequentially read a bunch of files (with file_get_contents), gzdecode them, json_decode the result, analyze the contents, throw most of it away, and store about 1% in an array.

Unfortunately, with each iteration (I traverse over an array containing the filenames), there seems to be some memory lost (according to memory_get_peak_usage, about 2-10 MB each time). I have double- and triple-checked my code; I am not storing unneeded data in the loop (and the needed data hardly exceeds about 10MB overall), but I am frequently rewriting (actually, strings in an array). Apparently, PHP does not free the memory correctly, thus using more and more RAM until it hits the limit.

Is there any way to do a forced garbage collection? Or, at least, to find out where the memory is used?

like image 635
DBa Avatar asked Mar 17 '10 11:03

DBa


People also ask

How to clear memory in PHP?

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 immediately frees the memory.

What is garbage collector PHP?

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.

What is memory leak in PHP?

What is a memory leak in PHP? A memory leak in PHP is a condition that causes sections of code to continue using memory even though that memory is no longer needed.


2 Answers

it has to do with memory fragmentation.

Consider two strings, concatenated to one string. Each original must remain until the output is created. The output is longer than either input.
Therefore, a new allocation must be made to store the result of such a concatenation. The original strings are freed but they are small blocks of memory.
In a case of 'str1' . 'str2' . 'str3' . 'str4' you have several temps being created at each . -- and none of them fit in the space thats been freed up. The strings are likely not laid out in contiguous memory (that is, each string is, but the various strings are not laid end to end) due to other uses of the memory. So freeing the string creates a problem because the space can't be reused effectively. So you grow with each tmp you create. And you don't re-use anything, ever.

Using the array based implode, you create only 1 output -- exactly the length you require. Performing only 1 additional allocation. So its much more memory efficient and it doesn't suffer from the concatenation fragmentation. Same is true of python. If you need to concatenate strings, more than 1 concatenation should always be array based:

''.join(['str1','str2','str3']) 

in python

implode('', array('str1', 'str2', 'str3')) 

in PHP

sprintf equivalents are also fine.

The memory reported by memory_get_peak_usage is basically always the "last" bit of memory in the virtual map it had to use. So since its always growing, it reports rapid growth. As each allocation falls "at the end" of the currently used memory block.

like image 172
James Lyons Avatar answered Sep 28 '22 08:09

James Lyons


In PHP >= 5.3.0, you can call gc_collect_cycles() to force a GC pass.

Note: You need to have zend.enable_gc enabled in your php.ini enabled, or call gc_enable() to activate the circular reference collector.

like image 27
Mo. Avatar answered Sep 28 '22 09:09

Mo.