JasonDavis
JasonDavis

Reputation: 48933

PHP memory usage increase after unsetting arrays?

I run the code below without unsetting the arrays and then with unsetting the arrays using PHP's

unset($array-here)

And the memory number increases when I use the unset. Any ideas why? ANd better yet, what is the proper way to free memory?

NOTICE: PLEASE, no preaching about pre-optimizing, its EVIL and all that, this is a test so don't lecture about it please and thank you.

//show current memory usage BEFORE
echo memory_get_usage() . "\n"; // 57960

//start timer
$start3 = microtime(true);
// arrays for header menu selector
$header_home = array('home'  => true);
$header_users = array('users.online' => true, 'users.location' => true, 'users.featured' => true, 'users.new' => true, 'users.browse' => true, 'users.search' => true, 'users.staff' => true);
$header_forum = array('forum' => true);
$header_more = array('widgets'  => true, 'news'  => true, 'promote'  => true, 'development'  => true, 'bookmarks'  => true, 'about'  => true);
$header_money = array('account.money' => true, 'account.store' => true, 'account.lottery' => true, 'users.top.money' => true);
$header_account = array('account'  => true);
$header_mail = array('mail.inbox' => true, 'mail.sentbox' => true, 'mail.trash' => true, 'bulletins.post' => true, 'bulletins.my' => true, 'bulletins' => true);

//run throught 1,000 iterations
for($i = 0; $i < $iterations; ++$i) {
if(isset($header_home[$p]))
    $current_home = 'current';
else if(isset($header_users[$p]))
    $current_users = 'current';
else if(isset($header_forum[$p]))
    $current_forum = 'current';
else if(isset($header_more[$p]))
    $current_more = 'current';
else if(isset($header_money[$p]))
    $current_money = 'current';
else if(isset($header_account[$p]))
    $current_account = 'current';
else if(isset($header_mail[$p]))
    $current_mail = 'current';
}
//unset the arrays
unset($header_money);
unset($current_home);
unset($current_users);
unset($current_forum);
unset($current_more);
unset($current_account);
unset($current_mail);

//show time
$end3 = microtime(true);
echo number_format($end3 - $start3, 7) . ' Time3 ARRAY<br />';

//show current memory usage AFTER
echo memory_get_usage() . "\n";

Upvotes: 4

Views: 10706

Answers (4)

Andr&#233; Hoffmann
Andr&#233; Hoffmann

Reputation: 3553

I don't know if that makes any difference, but you didn't unset $start3, $end3 and every other $home_xxx array than $home_money.

Also i would suggest keeping the benchmark more simple. Like only using one array for instance.

Keep it simple. It will make your test/benchmark more meaningful.

EDIT:

Just played around with it a bit..

First Test

<?php
$array = array();

echo "START:". memory_get_usage() . "\n";


for ( $i = 0; $i<1000; $i++ ) {
    $array[] = 'foo';
}

echo "BEFORE UNSET: " . memory_get_usage() . "\n";

unset($array);
echo "AFTER UNSET: " . memory_get_usage() . "\n";

sleep(120);
echo "AFTER A WHILE: " . memory_get_usage() . "\n";

Output:

START:53632
BEFORE UNSET: 146360
AFTER UNSET: 118848
AFTER A WHILE: 118848

Second test:

<?php
$array = array();

echo "START:". memory_get_usage() . "\n";


for ( $i = 0; $i<1000; $i++ ) {
    $array[] = 'foo';
}

echo "BEFORE UNSET: " . memory_get_usage() . "\n";

for ( $i = 0; $i<count($array); $i++ ) {
    unset($array[$i]);
}
unset($array);
echo "AFTER UNSET: " . memory_get_usage() . "\n";

Output:

START:53944
BEFORE UNSET: 146680
AFTER UNSET: 119128

So the theory that unset only schedules for garbage collection doesn't hold(at least not in PHP 5.2.8, but then again they changed a lot in the GC of PHP 5.3).

I'm afraid there's not much more that you can do than unset :-(

Upvotes: 1

Peter Bailey
Peter Bailey

Reputation: 105878

unset() is not a "force garbage collection" mechanism.

So calling unset() doesn't mean the memory that variable was holding is instantly available, it just means that variable is scheduled for garbage collection. The PHP engine does that on its own schedule.

Upvotes: 1

Pascal MARTIN
Pascal MARTIN

Reputation: 401002

I did a very quick test, after doing this :

  • declaring $iterations = 10; at the beginning of the script
  • using $p and not $i in the for loop (you are using $p to access array elements, and not $i)
  • adding a line to display used memory before the unsets

I am getting this, using PHP 5.3.1 (today's snapshot) :

328616
332176
331728

The three outputs are :

  • first one : the beginning of the script (the one which says "show current memory usage BEFORE")
  • second one : the one I added before the calls to unset ; just after the end of the for loop
  • third one : the one you put at the end of your script.

So, the unsets do actually provoke the liberation of some memory, and not the increase of memory used ;-)

But only a pretty small portion of the allocated memory is freed...


Now, the question might be "what is causing some memory to be used and not freed, event if I call unset on the arrays" -- actually, it is probably what you first meant ?

Well, I suppose unsetting the arrays themselves doesn't force PHP to free the memory allocated for items inside the arrays...

Like this note on the unset manual page says (quoting) :

unset() does just what it's 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.

If you are doing $whatever = null; then you are rewriting variable's data. You might get memory freed / shrunk faster, but it may steal CPU cycles from the code that truly needs them sooner, resulting in a longer overall execution time.

And, actually, this might look interesting ;-)

Still, doing a couple of quick tests doesn't get anything quite interesting ; I suppose my script / data is not big enough to force PHP to free unused memory, or something like this...


Note : if I use gc_collect_cycles (PHP >= 5.3) to force a garbage collection after the unsets, it doesn't change a thing -- I suppose it's because there is no "lost cycle".


*BTW : running your code gave me quite a couple notices (the $p vs $i, for instance) ; do you develop with error_reporting set to report notices ? *

Upvotes: 10

p4bl0
p4bl0

Reputation: 3906

You're first call to memory_get_usage() is before arrays exist. You should do it between the creations + filling of your arrays and your unset()'s

Here what you see is just that more memory is used at the end of the script than at the beginning.

Upvotes: 3

Related Questions