Re: Why does count() make copies of arrays?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Robert Cummings wrote:
On Mon, 2006-08-14 at 13:16 -0400, Adam Zey wrote:
I was writing a shell script in PHP (4.4.2) that dealt with a rather large array. To figure out what I needed the new memory limit to be, I did a memory_get_usage() at the end of my script, and came up with about 5.5MB. I then set the memory limit to 8MB.

When I tried to run it, the script ran out of memory on the line:

$numwords = count($words);

However, when I switched to simply incrementing $numwords every time I added an element to $words, the memory limit of 8MB was fine.

So my question is, if PHP does copy-on-write, why does PHP make a copy of an array when you use count() on it, which should NOT be modifying the array?

For some reason the memory_get_usage() function wouldn't appear in my
PHP compilation even after using the --enable-memory-limit flag, and
rather than dig very deep, I whipped up the following script to test
your issue (under PHP 4.2.2):

<?php

    //echo 'Mem Usage: '.memory_get_usage()."\n";

    $foo = array();

    for( $i = 0; $i < 10000000; $i++ )
    {
        $foo[$i] = $i;
    }

    echo 'Created big array!'."\n";
    sleep( 10 );

    //echo 'Mem Usage: '.memory_get_usage()."\n";

    $numEntries = count( $foo );

    echo 'Counted big array!'."\n";
    sleep( 10 );

    //echo 'Mem Usage: '.memory_get_usage()."\n";
?>

Using the following command:

    watch -n 0 'ps awxu | grep foo.php | grep -v grep'

I got the following snapshots during the two sleep steps:

    rob      16018 66.7 44.7 935084 928684 pts/7   S+   17:11
0:18 /usr/local/bin/php -qC ./foo.php

    rob      16018 43.9 44.7 935084 928684 pts/7   S+   17:11
0:18 /usr/local/bin/php -qC ./foo.php

Which indicated no change from the 935 megs of memory already allocated
before the count().

You've either encountered a bug in your version, or a confounding
variable :)

Cheers,
Rob.

That's the thing, count only creates a duplicate of the array (or consumes massive amounts of memory) *during* the call of count(). It frees the memory right after. The problem is that if you've got a 2MB array, you can't call count() on it because the temporarily increased memory usage will break the 4MB memory limit.

Here's a better test case:

1) Ensure the memory limit is enabled and set to 4MB
2) Create an array that is 3MB in size
3) Try to call count() on that array

With PHP 4.4.2, this will fail, because count will try to copy the array (or do something else that consumes a lot of memory). If you increase the memory limit to compensate, the memory usage goes back down immediately after the count call. For this reason, memory_get_usage() will never show the extra memory usage; it's allocated and freed entirely during the count() call.

Regards, Adam.

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux