On Mon, 2006-08-14 at 17:24 -0400, Adam Zey wrote:
> 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.
When I ran the original test I was watching the process, it generally
takes more than a second on most system to allocate several hundred
megabytes which would have exposed your problem as a spike. At any
rate...
I figured out my problem with the recompile and then ran the script with
appropriate settings. On the first run I determined the memory required
and then for the second run I set the memory to an amount very close to
what was used. Here is second script:
#!/usr/local/bin/php -qC
<?php
ini_set( 'memory_limit', '627150412' );
echo 'Mem Usage: '.memory_get_usage()."\n";
$foo = array();
for( $i = 0; $i < 10000000; $i++ )
{
$foo[$i] = $i;
}
echo 'Created big array!'."\n";
echo 'Mem Usage: '.memory_get_usage()."\n";
$numEntries = count( $foo );
echo 'Counted big array!'."\n";
echo 'Mem Usage: '.memory_get_usage()."\n";
?>
Following I the output:
Mem Usage: 41296
Created big array!
Mem Usage: 627150256
Counted big array!
Mem Usage: 627150320
Changing the memory limit from '627150412' to '627150212' result sin the
expected memory limit exception:
Mem Usage: 41296
<br />
<b>Fatal error</b>: Allowed memory size of 627150212 bytes exhausted
(tried to allocate 12 bytes) in <b>/home/suds/foo.php</b> on line
<b>10</b><br />
So I'm not experiencing your memory issue since due to the the immense
size of the array I'm creating it would certainly show if a copy was
performed. That said (and maybe this is related to the recent memory
thread on internals that I sort of skipped over), I'm very surprised
that while I allowed '627150412' bytes for memory, that the PHP process
climbed to 900+ megs. It seems as though it doesn't account for it's own
usage of memory, which is extremely misleading. Admittedly this kind of
allocation on a production web site would normally be considered
ludicrous, it still strikes me that the memory_limit ini setting is
somewhat misleading -- in this case by about 30%.
Cheers,
Rob.
--
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php