|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2009-06-22 11:41 UTC] zoe@php.net
Description: ------------ An excessive about of memory is used when a class which extends FilterIterator is used to filter for certain file types when scanning a source tree. Reproduce code: --------------- A small benchmark is provided in the tar file here:http://filebin.ca/okgvtt/memcheck.tar The file contains three tests which all use code in Util.php. To run the tests edit the shell script memcheck to add the top level directory of a PHP source tree as input to each test. Then just execute the shell script. The benchmarks produce a list of directories which contain .phpt files, the memory usage when the class PhptFilterIterator is used is 20 times higher than the other two methods. Expected result: ---------------- Would expect the memory usage to be similar. Actual result: -------------- Memory usage is 20 times higher. PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 18:00:01 2025 UTC |
Below is a simplified testcase which I think exposes the same leak. '/manyFiles' is a directory containing 10000 files. <?php $rii = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('/manyFiles') ); function noop() {} echo "noop call in loop (no leak) : "; foreach ($rii as $v) { noop($v); } echo memory_get_usage() . PHP_EOL; echo "strlen call in loop (leak on 53) : "; foreach ($rii as $v) { strlen($v); } echo memory_get_usage() . PHP_EOL; ?> Output on php52: noop call in loop (no leak) : 66176 strlen call in loop (leak on 53) : 66176 Output on php53: noop call in loop (no leak) : 337448 strlen call in loop (leak on 53) : 6028496Testcase below shows that the issue relates to an implicit cast to string on an SplFileInfo object when retrieved from a RecursiveDirectoryIterator during iteration. <?php $rdi = new RecursiveDirectoryIterator('/manyFiles'); echo "SplFileInfo explicit cast to string: "; foreach ($rdi as $v) { strlen((string)$v); } //OK echo memory_get_usage(true) . PHP_EOL; echo "SplFileInfo implicit cast to string: "; foreach ($rdi as $v) { strlen($v); } //Leaky echo memory_get_usage(true) . PHP_EOL; ?> php52: SplFileInfo explicit cast to string: 262144 SplFileInfo implicit cast to string: 262144 php53: SplFileInfo explicit cast to string: 524288 SplFileInfo implicit cast to string: 6291456The following patch fixes the issue. Might not be the nicest way and probably some other code in there might need a similar fix. Index: Zend/zend_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_API.c,v retrieving revision 1.296.2.27.2.34.2.64 diff -u -p -r1.296.2.27.2.34.2.64 zend_API.c --- Zend/zend_API.c 4 Jun 2009 18:20:42 -0000 1.296.2.27.2.34.2.64 +++ Zend/zend_API.c 23 Jun 2009 21:33:04 -0000 @@ -254,10 +254,13 @@ ZEND_API int zend_get_object_classname(c static int parse_arg_object_to_string(zval **arg, char **p, int *pl, int type TSRMLS_DC) /* {{{ */ { if (Z_OBJ_HANDLER_PP(arg, cast_object)) { + zval tmp; + INIT_PZVAL(&tmp); SEPARATE_ZVAL_IF_NOT_REF(arg); - if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, type TSRMLS_CC) == SUCCESS) { - *pl = Z_STRLEN_PP(arg); - *p = Z_STRVAL_PP(arg); + if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, &tmp, type TSRMLS_CC) == SUCCESS) { + *pl = Z_STRLEN(tmp); + *p = Z_STRVAL(tmp); + zval_dtor(&tmp); return SUCCESS; } }