php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48528 mysqlnd causes PDO/MySQLi to leak memory
Submitted: 2009-06-11 12:17 UTC Modified: 2009-11-03 09:45 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: bugs dot php dot net at moesen dot nu Assigned:
Status: Closed Package: MySQL related
PHP Version: 5.3CVS-2009-06-11 (snap) OS: Linux 2.6
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: bugs dot php dot net at moesen dot nu
New email:
PHP Version: OS:

 

 [2009-06-11 12:17 UTC] bugs dot php dot net at moesen dot nu
Description:
------------
PHP 5.3 leaks memory when using the MySQL functions, both through PDO and MySQLi directly. When recompiled without mysqlnd, the same code works fine.

./configure --with-mysql=shared,mysqlnd --with-mysqli=shared,mysqlnd --with-pdo-mysql=shared,mysqlnd [ . . . ]

Recompiled today's snapshot without the ',mysqlnd'.

Reproduce code:
---------------
PDO:
$db = new PDO($dsn, $user, $pass);
$stmt = $test->prepare('SELECT * FROM tech_eciffOkcab.crawlPriceComp');
$result = $stmt->execute();
while($result && $row = $stmt->fetch(PDO::FETCH_ASSOC)) {
	echo memory_get_usage(), "\n";
}

MySQLi:
$db = new MySQLi($host, $user, $pass);
$result = $db->query('SELECT * FROM tech_eciffOkcab.crawlPriceComp');
while ($result && $row = $result->fetch_assoc()) {
        echo memory_get_usage(), "\n";
}


Expected result:
----------------
Consistent memory_get_usage();

I.e., no extra memory required, and thus no out-of-memory errors.

Actual result:
--------------
Linearly increasing memory_get_usage();

PDO:
23168400
23169064
...
33552804
33552916
-> OOM and segfault.

MySQLi:
23168216
23168700
...
33552812
33552924
-> OOM and segfault.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-12 07:36 UTC] andrey@php.net
Do you really get OOM with mysqlnd? memory_get_usage() is constant with libmysql because libmysql allocates its memory with malloc while Zend and all PHP functions mostly use emalloc. emalloc counts the allocated memory. libmysql's allocations are hidden.
I tried your script, created a simple table with the same name and 
- int
- double
- varchar
- decimal
columns.
I have 33 rows. Here is the output when the data is fetched with MYSQLI_STORE_RESULT, which is the default:
361756 <- before $result = $db->query
366384
366656
366928
367200
367472
367744
368016
368288
368560
368832
369104
369376
369648
369920
370192
370464
370736
371008
371280
371552
371824
372096
372368
372640
372912
373184
373456
373728
374000
374272
374544
374816
375088
362840 <- this is the result after I do $result->free_result(), which means that the memory doesn't leak. Most of it is reclaimed. It can be that Zend also cache some zvals in its zval cache, which means that memory has not leaked and is there for further usage. 

Here is with MYSQLI_USE_RESULT:
361756  <- before $result = $db->query
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
365764
362840 <- After $result->free_result()

So, as you can see the memory usage with USE_RESULT doesn't jump, for a reaon. Because data is not stored on the client side. With libmysql you cannot see it, but the usage is there.


 [2009-06-16 08:31 UTC] bugs dot php dot net at moesen dot nu
> libmysql's allocations are hidden.
OK, that explains the numbers. Thanks.

> Do you really get OOM with mysqlnd?
Yes, for the same dataset.

> as you can see the memory usage with USE_RESULT doesn't jump
Thanks for that pointer. I completely missed it in the documentation, and since we never had any problems before switching over to 5.3, I never needed it. The human equivalent of lazy evaluation, I guess.

So if I understand it correctly, libmysql is not subject to PHP's memory limit, whereas mysqlnd is?
 [2009-06-20 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2009-10-30 12:32 UTC] guenter at grodotzki dot ph
same problem here, though with the normal mysql_query + mysql_fetch* functions
 [2009-11-03 09:45 UTC] uw@php.net
Duplicate of http://bugs.php.net/bug.php?id=48343 - there is no leak, mysqlnd and libmysql work differently. 
 [2013-07-22 21:05 UTC] ben at ajmadison dot com
The answer is not 100% correct.

It is true that libmysqlclient hides the amount of allocted memory, while mysqlnd shows up in PHP.

Here are the results I obtained using the latest PHP 5.5.1 build.

When measured by "ps aux|grep php|grep mysql" though, mysqlnd memory usage keeps climbing during loop iteration, getting to over 5 times the amount of memory allocated during mysql_query. libmysqlclient memory usage only goes up while  mysql_query is running, and stays constant during iteration.

Why does mysqlnd use so much more memory than lilbmysqlclient, as reported by: "ps aux|grep php|grep mysql"? Why does iterating throught he loop use 5 times+ the memory of mysql_query?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri May 17 05:01:31 2024 UTC