On 03/02/13 15:27, Hans-Juergen Petrich wrote:
In this example (using php-5.4.11 on Linux) the memory will grow
non-stop:
for ( $fp = fopen('/dev/urandom', 'rb'); true;) {
eval ('$ano_fnc = function() {$x = "'.bin2hex(fread($fp,
mt_rand(1, 10000))).'";};');
echo "Mem usage: ".memory_get_usage()."\n";
}
But in this example not:
for ( $fp = fopen('/dev/urandom', 'rb'); true;) {
eval ('$ano_fnc = function() {$x = "'.bin2hex(fread($fp,
10000)).'";};');
echo "Mem usage: ".memory_get_usage()."\n";
}
Hans-Juergen, I've raised a bugrep https://bugs.php.net/bug.php?id=64291
which you might want to review and add any appropriate comments. I had
to think about this one. It's worthwhile observing that this second
example is the only occasion, as far as I know, that PHP does any
garbage collection of code objects before request shutdown. For example
create_function() objects are given the name "\0LambdaN" where N is the
count of the number of created functions so far in this request. They
are registered in the function table and persist until request
shutdown. That's the way PHP handles them by design.
As I said in the bugrep, the normal behaviour of persistence is what you
want because if you think about the normal use of the anonymous
function, say
while (!feof($fp)) {
$line = preg_replace_callback(
'|<p>\s*\w|',
function($matches) {return strtolower($matches[0]);},
gets($fp)
);
echo $line;
}
Then the anonymous function is compiled once and rebound to the closure
object which is passed as the
second argument for the callback each time through the loop. OK, doing
the closure CTOR/DTOR once per loop. is not the cleverest of ideas and
this is the sort of thing that would be hoisted out of the loop in a
language which did such optimization, but PHP doesn't. It's a LOT better
that compiling a new function each loop (which is how Example #1 on
http://php.net/manual/en/function.preg-replace-callback.php does it!)
This is what you want to happen.
It's just too complicated for PHP to work out if the function might or
not be rebound to. I suspect the bug here is really the implicit
assumption that the magic function name generated by the
eval ('$ano_fnc = function() { ... }');
is unique, but as your examples shows, thanks to garbage collection and
reuse of memory, sometimes it isn't. In these circumstances thank to
the use of a hash update and the table DTOR the old one is deleted.
So assume that what you are doing is exploiting a bug, so my advice is
not to do this. It might be fixed in a future release.
Regards Terry