Bug #77308 [Opn]: Unbuffered queries memory leak
| From: | nikic@php.net | Date: | Wed, 02 Jan 2019 11:14:56 +0000 |
| Subject: | Bug #77308 [Opn]: Unbuffered queries memory leak | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-218738@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=77308&edit=1
ID: 77308
Updated by: nikic@php.net
Reported by: sjon at hortensius dot net
Summary: Unbuffered queries memory leak
Status: Open
Type: Bug
Package: MySQL related
Operating System: archlinux
PHP Version: 7.3.0
-Assigned To:
+Assigned To: dmitry
Block user comment: N
Private report: N
New Comment:
@dmity: Probably related to the mysqlnd arena improvements.
Massif trace:
97.88% (10,719,359B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->91.19% (9,987,510B) 0x953317: __zend_malloc (zend_alloc.c:2904)
| ->76.79% (8,409,934B) 0x9525C8: _emalloc (zend_alloc.c:2494)
| | ->73.05% (8,000,688B) 0x89116A: _mysqlnd_emalloc (mysqlnd_alloc.c:99)
| | | ->72.90% (7,984,000B) 0x8D3CDD: mysqlnd_arena_alloc (mysqlnd_block_alloc.c:66)
| | | | ->72.90% (7,984,000B) 0x8D430D: mysqlnd_mempool_get_chunk (mysqlnd_block_alloc.c:148)
| | | | ->72.90% (7,984,000B) 0x8A119A: php_mysqlnd_read_row_ex (mysqlnd_wireprotocol.c:1384)
| | | | ->72.90% (7,984,000B) 0x8A358B: php_mysqlnd_rowp_read (mysqlnd_wireprotocol.c:1724)
| | | | ->72.90% (7,984,000B) 0x8BF0CE: mysqlnd_mysqlnd_result_unbuffered_fetch_row_c_pub
(mysqlnd_result.c:677)
| | | | ->72.90% (7,984,000B) 0x8C5755: mysqlnd_mysqlnd_res_fetch_row_c_pub
(mysqlnd_result.c:1757)
| | | | ->72.90% (7,984,000B) 0x65C177: pdo_mysql_stmt_fetch (mysql_statement.c:660)
| | | | ->72.90% (7,984,000B) 0x64853F: do_fetch_common (pdo_stmt.c:676)
| | | | ->72.90% (7,984,000B) 0x648BF1: do_fetch (pdo_stmt.c:831)
| | | | ->72.90% (7,984,000B) 0x64F1BF: pdo_stmt_iter_move_forwards
(pdo_stmt.c:2447)
| | | | ->72.90% (7,984,000B) 0xA214AA: ZEND_FE_FETCH_R_SPEC_VAR_HANDLER
(zend_vm_execute.h:21484)
| | | | ->72.90% (7,984,000B) 0xA624CD: execute_ex (zend_vm_execute.h:57707)
| | | | ->72.90% (7,984,000B) 0xA656DA: zend_execute
(zend_vm_execute.h:60833)
| | | | ->72.90% (7,984,000B) 0x98AE19: zend_execute_scripts
(zend.c:1568)
| | | | ->72.90% (7,984,000B) 0x8F0BE1: php_execute_script
(main.c:2630)
| | | | ->72.90% (7,984,000B) 0xA6842F: do_cli (php_cli.c:997)
| | | | ->72.90% (7,984,000B) 0xA695A5: main (php_cli.c:1389)
Presumably freeing chunks from the arena doesn't work properly anymore.
Previous Comments:
------------------------------------------------------------------------
[2019-01-02 10:58:17] nikic@php.net
Test script including (slow) table generation:
<?php
ini_set('memory_limit', '8M');
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'php-test',
'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$pdo->exec("DROP TABLE IF EXISTS large_table");
$pdo->exec("CREATE TABLE large_table (id int)");
for ($j = 0; $j < 100; $j++) {
$query = "INSERT INTO large_table (id) VALUES ";
for ($i = 0; $i < 10000; $i++) {
$query .= "($i), ";
}
$query .= "($i)";
$pdo->exec($query);
}
$result = $pdo->query("SELECT * FROM large_table");
foreach ($result as $i => $row)
if ($i % 10000 === 0)
printf("%10s %10s\n", $i, memory_get_usage());
I'm also getting a
Warning: Packets out of order. Expected 231 received 48. Packet size=3422212 in Unknown on line 0
after the memory limit error.
------------------------------------------------------------------------
[2018-12-28 21:06:31] cweiske@php.net
This breaks Roundcube webmail, see https://bugs.archlinux.org/task/61139.
Happens here with 7.3.0-2 (Debian 9)
------------------------------------------------------------------------
[2018-12-17 09:16:01] sjon at hortensius dot net
Description:
------------
commit f1f1f6 broke unbuffered queries in mysqlnd; there is a memory leak causing php to run out of
memory
Test script:
---------------
<?php
ini_set('memory_limit', '8M');
$pdo = new PDO('mysql:host=*;dbname=*', '*', '*');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$result = $pdo->query("SELECT * FROM large_table");
foreach ($result as $i => $row)
if ($i % 10000 === 0)
printf("%10s %10s\n", $i, memory_get_usage());
Expected result:
----------------
reasonable constant memory usage, eg:
0 427648
10000 427936
20000 427968
30000 427968
40000 427936
Actual result:
--------------
0 427296
10000 2000288
20000 3622336
30000 5260736
40000 6915488
Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 16384 bytes) in /php
on line 10
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=77308&edit=1